7

【基础系列】实现一个自定义的@Autowired(应用篇)

 3 years ago
source link: https://spring.hhui.top/spring-blog/2021/02/23/210223-SpringBoot%E5%BA%94%E7%94%A8%E7%AF%87%E4%B9%8B%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AA%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84-Autowired/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
logo.jpg

【基础系列】实现一个自定义的@Autowired(应用篇)

在Spring的生态中,借助@Autowired注解来实现依赖注入,可以说是非常普遍的事情了,如果让我们自定义一个注解,也实现类似的功能,那么我们可以怎么做呢?

本文介绍如何实现一个自定义的@Autowired,实现依赖服务注入

主要知识点:

  • BeanPostProcessor
  • 代理类创建

I. 项目环境

本项目借助SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA进行开发

下面是核心的pom.xml(源码可以再文末获取)

<!-- 这个依赖是干嘛的,后文会介绍 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
</dependencies>

II. 实现姿势

1. 代理封装类

借助Spring的Enhance来实现代理类生成,比如一个基础的工具类如下,用于自定义注入的增强

public class ProxyUtil {
public static <T> T newProxyInstance(Class<?> targetClass, InvocationHandler invocationHandler,
ProxyUtil.CallbackFilter filter) {
if (targetClass == null) {
return null;
} else {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setUseCache(true);
enhancer.setCallback(new ProxyUtil.SimpleMethodInterceptor(invocationHandler, filter));
// 无参构造方法
return (T) enhancer.create();
}
}

public interface CallbackFilter {
boolean accept(Method var1);
}

private static class SimpleMethodInterceptor implements MethodInterceptor, Serializable {
private transient InvocationHandler invocationHandler;
private transient ProxyUtil.CallbackFilter filter;

public SimpleMethodInterceptor(InvocationHandler invocationHandler, ProxyUtil.CallbackFilter filter) {
this.invocationHandler = invocationHandler;
this.filter = filter;
}

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return this.filter.accept(method) ? this.invocationHandler.invoke(o, method, objects) : methodProxy.invokeSuper(o, objects);
}
}
}

2. 自定义注解

参照@Autowired的定义,实现一个自定义的注解(缩减版)

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AutoInject {
}

3. 自定义注入

实现BeanPostProcessor,在bean初始化之后,扫描field/method,为了做一个区分,下面创建一个代理类,注入依赖

@Component
public class AutoInjectPostProcessor implements BeanPostProcessor {

private ApplicationContext applicationContext;

public AutoInjectPostProcessor(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Class<?> clazz = bean.getClass();
do {
for (final Field field : clazz.getDeclaredFields()) {
final AutoInject annotation = AnnotationUtils.findAnnotation(field, AutoInject.class);
if (annotation != null) {
ReflectionUtils.makeAccessible(field);
ReflectionUtils.setField(field, bean, processInjectionPoint(field.getType()));
}
}
for (final Method method : clazz.getDeclaredMethods()) {
final AutoInject annotation = AnnotationUtils.findAnnotation(method, AutoInject.class);
if (annotation != null) {
final Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1) {
throw new BeanDefinitionStoreException(
"Method " + method + " doesn't have exactly one parameter.");
}
ReflectionUtils.makeAccessible(method);
ReflectionUtils.invokeMethod(method, bean,
processInjectionPoint(paramTypes[0]));
}
}
clazz = clazz.getSuperclass();
} while (clazz != null);
return bean;
}

// 创建代理类,在具体方法执行前后输出一个日志
protected <T> T processInjectionPoint(final Class<T> injectionType) {
return ProxyUtil.newProxyInstance(injectionType, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("do before " + method.getName() + " | " + Thread.currentThread());
try {
Object obj = applicationContext.getBean(injectionType);
return method.invoke(obj, args);
} finally {
System.out.println("do after " + method.getName() + " | " + Thread.currentThread());
}
}
}, new ProxyUtil.CallbackFilter() {
@Override
public boolean accept(Method var1) {
return true;
}
});
}
}

接下来验证一下自定义注入方式

@Component
public class DemoService {

public int calculate(int a, int b) {
doBefore();
return a + b;
}

private void doBefore() {
System.out.println("-------- inner ----------: " + Thread.currentThread());
}
}

@Component
public class DemoService2 {

public int calculate(int a, int b) {
doBefore();
return a + b;
}

private void doBefore() {
System.out.println("-------- inner ----------: " + Thread.currentThread());
}
}

@Service
public class RestService {
@AutoInject
private DemoService demoService;

private DemoService2 demoService2;

@AutoInject
public void setDemoService2(DemoService2 demoService2) {
this.demoService2 = demoService2;
}

public void test() {
int ans = demoService.calculate(10, 20);
System.out.println(ans);

ans = demoService2.calculate(11, 22);
System.out.println(ans);
}
}

执行完毕之后,输出日志如

do before calculate | Thread[main,5,main]
-------- inner ----------: Thread[main,5,main]
do after calculate | Thread[main,5,main]
30

do before calculate | Thread[main,5,main]
-------- inner ----------: Thread[main,5,main]
do after calculate | Thread[main,5,main]
33

II. 其他

1. 一灰灰Blog

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

一灰灰blog

打赏 如果觉得我的文章对您有帮助,请随意打赏。

分享到


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK