如何自定义@autowired注解?
在上一章节,我们分享了@Autowire注解方式的原理以及源码,对 AutowiredAnnotationBeanPostProcessor这个类的核心方法做了深入分析,本章将对自定义属性注入进行详细分析。
首先我们还是看到这个类AutowiredAnnotationBeanPostProcessor:
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
可以看到AutowiredAnnotationBeanPostProcessor的默认构造器做了一件事情,就是这里this.autowiredAnnotationTypes.add(Autowired.class);我们可以很直观的看到Autowired,没错这里就是我们的注解类,如果不行的话我们再看看这个集合autowiredAnnotationTypes
可以看到这里的autowiredAnnotationTypes装的是注解类型,因此可以断定这就是存放我们定义的注解信息,好了,话题先到这里,等会我们再深度分析,下面我们就开始如何基于Spring自定义依赖注入注解,这里一共有两种方式,第一种就十分简单,我们可以直接在注解上加上@Autowired注解,我们看下面个例子:
首先创建一个注解类名MyAutowired
package com;
import org.springframework.beans.factory.annotation.Autowired;
import java.lang.annotation.*;
/**
* @author 七天0
* @date 2020/12/16 0016 22:58
* 概要 :
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Autowired
public @interface MyAutowired {
}
然后在创建一个User1类和一个User2类
package com;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class User2 implements User{
@MyAutowired
private User user1;
@PostConstruct
public void postConstruct(){
System.out.println(user1);
}
}
package com;
import org.springframework.stereotype.Component;
@Component
public class User1 implements User {
}
代码很简单就不做解释了,然后我们开始写配置类和测试类
import com.MyImportBeanDefinitionRegistrar;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.context.annotation.*;
@Configuration
@ComponentScan("com")
/*@EnableAspectJAutoProxy*/
/*@Import(MyImportBeanDefinitionRegistrar.class)*/
public class AppConfig {
}
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext=
new AnnotationConfigApplicationContext(AppConfig.class);
}
}
注意User2类里面的user1属性,我们可以很清楚的看到我用的是自定义注解 @MyAutowired,然后我们测试一下
Connected to the target VM, address: '127.0.0.1:54489', transport: 'socket'
com.User1@549949be
Disconnected from the target VM, address: '127.0.0.1:54489', transport: 'socket'
Process finished with exit code 0
这里打印了User1,说明我们注入成功了,那么也就是说这样就可以自定义我们的属性注入注解,当然这里虽然简单但是太过于死板,于是我们用第二种方式。
我们还是用案例来解释,首先修改一下我们的注解类
package com;
import org.springframework.beans.factory.annotation.Autowired;
import java.lang.annotation.*;
/**
* @author 七天0
* @date 2020/12/16 0016 22:58
* 概要 :
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowired {
}
取消@Autowired注解,然后我们再更新下我们的配置类
import com.MyAutowired;
import com.MyImportBeanDefinitionRegistrar;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.context.annotation.*;
import java.lang.annotation.Annotation;
import java.util.LinkedHashSet;
import java.util.Set;
import static java.util.Arrays.asList;
import static org.springframework.context.annotation.AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME;
@Configuration
@ComponentScan("com")
/*@EnableAspectJAutoProxy*/
/*@Import(MyImportBeanDefinitionRegistrar.class)*/
public class AppConfig {
//AutowiredAnnotationBeanPostProcessor
@Bean(name = AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)
public AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor(){
AutowiredAnnotationBeanPostProcessor beanPostProcessor=
new AutowiredAnnotationBeanPostProcessor();
Set<Class<? extends Annotation>> autowiredAnnotationTypes
=new LinkedHashSet<>(asList(MyAutowired.class));
beanPostProcessor.setAutowiredAnnotationTypes(autowiredAnnotationTypes);
return beanPostProcessor;
}
}
然后在更新下我们的User类
package com;
import org.springframework.stereotype.Component;
@Component
public class User1 implements User {
}
package com;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class User2 implements User{
@MyAutowired
private User user1;
@Autowired
private User user2;
@PostConstruct
public void postConstruct(){
System.out.println(user1);
System.out.println(user2);
}
}
这里的User2类我们用了@Autowired和 @MyAutowired,然后我们在测试下我们的代码
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext=
new AnnotationConfigApplicationContext(AppConfig.class);
}
}
测试结果如下
com.User1@22f59fa
null
Process finished with exit code 0
可以看到我们的user2注入失败了,而我们的自定义类成为了自动注入得类,这是为什么?原因就在我们的AppConfig类里面,请大家注意这行代码beanPostProcessor.setAutowiredAnnotationTypes(autowiredAnnotationTypes);我们看下图
可以看到这里Spring会清空原有的东西,然后再进行添加,因此这也是为什么Spring自己的@Autowired会失效,是不是突然觉得Spring的设计有那么点牛逼,哈哈,这里再提出一个问题,我们的name = AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME为什么一定要是它,如果不是它,效果会一样吗?为什么?这里读者可以尝试一下,然后自行自考,最后笔者做一点提示,注意Spring内部创建的默认AutowiredAnnotationBeanPostProcessor的BeanName是什么,好了本章内容分享到这里