定义三个 bean
,名称分别为 Bean1
、Bean2
、Bean3
bean1
中依赖了Bean2
和Bean3
bean2
通过@Autowired
的注解注入Bean3
通过@Resource
注解注入@Value
注解注入一个Java
的环境变量JAVA_HOME
的值init()
和destroy()
,分别加上@PostConstruct
和@PreDestroy
Bean4
——使用ConfigurationPropertiesBean1
@Slf4j
public class Bean1 {
private Bean2 bean2;
@Autowired
public void setBean2(Bean2 bean2) {
log.info("@Autowired 生效:{}", bean2);
this.bean2 = bean2;
}
@Autowired
public void setJava_home(@Value("${JAVA_HOME}") String java_home) {
log.info("@Value 生效:{}", java_home);
this.java_home = java_home;
}
private Bean3 bean3;
@Resource
public void setBean3(Bean3 bean3) {
log.info("@Resource 生效:{}", bean3);
this.bean3 = bean3;
}
private String java_home;
@PostConstruct
public void init() {
log.info("@PostConstruct 生效:{}");
}
@PreDestroy
public void destroy() {
log.info("@PreDestroy 生效:{}");
}
@Override
public String toString() {
return "Bean1{" +
"bean2=" + bean2 +
", bean3=" + bean3 +
", java_home='" + java_home + '\'' +
'}';
}
}
Bean2、Bean3、Bea4
public class Bean2 {
}
public class Bean3 {
}
@ConfigurationProperties(prefix = "java")
@Slf4j
public class Bean4 {
}
这里使用GenericApplicationContext
来探究@Autowired
、@Value
、@Resource
、@PostConstruct
、@PreDestroy
以及springboot
项目中的@ConfigurationProperties
这些注解分别是由哪个后处理器来解析的。
GenericApplicationContext
是一个【干净】的容器,默认不会添加任何后处理器,方便做测试,这里用DefaultListableBeanFactory
也可以完成测试,只是会比使用GenericApplicationContext
麻烦一些。
public class TestBeanPostProcessor {
public static void main(String[] args) {
// GenericApplicationContext 是一个【干净】的容器
GenericApplicationContext context = new GenericApplicationContext();
// 用原始方法注册三个Bean
context.registerBean("bean1", Bean1.class);
context.registerBean("bean2", Bean2.class);
context.registerBean("bean3", Bean3.class);
context.registerBean("bean4", Bean4.class);
//解决No qualifying bean of type 'java.lang.String' available
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// @Autowired @value
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
// @Resource @PostConstruct @PreDestroy
context.registerBean(CommonAnnotationBeanPostProcessor.class);
// ConfigurationProperties
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
// 初始化容器
context.refresh();
System.out.println("Bean4:"+context.getBean(Bean4.class));
// 销毁容器
context.close();
}
}
结论
@Autowired
注解对应的后处理器是AutowiredAnnotationBeanPostProcessor
@Value
注解需要配合@Autowired
注解一起使用,所以也用到了AutowiredAnnotationBeanPostProcessor
后处理器,然后@Value
注解还需要再用到ContextAnnotationAutowireCandidateResolver
解析器,否则会报错;@Resource
、@PostConstruct
、@PreDestroy
注解对应的后处理器是CommonAnnotationBeanPostProcessor
;@ConfigurationProperties
注解对应的后处理器是ConfigurationPropertiesBindingPostProcessor
。
@Autowired
注解解析用到的后处理器时AutowiredAnnotationBeanPostProcessor
这个后处理器就是通过调用
postProcessProperties(PropertyValues pvs, Object bean, String beanName)
完成注解的解析和注入的功能看源码 postProcessProperties 这个方法 1.方法中又调用了一个私有的方法findAutowiringMetadata(beanName, bean.getClass(), pvs),其返回值InjectionMetadata中封装了被@Autowired注解修饰的属性和方法 2.然后会调用InjectionMetadata.inject(bean1, "bean1", null)进行依赖注入
- 1
- 2
- 3
- 4
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 创建过程、依赖注入、初始化
beanFactory.registerSingleton("bean2",new Bean2());
beanFactory.registerSingleton("bean3",new Bean3());
// @Value
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// 1.查找那些属性、方法加了@Autowired,这称为 InjectionMetadata
AutowiredAnnotationBeanPostProcessor postProcessor = new AutowiredAnnotationBeanPostProcessor();
postProcessor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1();
System.out.println("前bean1:" + bean1);
postProcessor.postProcessProperties(null,bean1,"bean1");
System.out.println("后bean1:" + bean1);
}
反射调用
AutowiredAnnotationBeanPostProcessor
类中findAutowiringMetadata
的方法
调用 InjectionMetadata 来进行依赖注入,注入时按类型查找值
// 2.调用 InjectionMetadata 来进行依赖注入,注入时按类型查找值
metadata.inject(bean1,"bean1",null);
System.out.println("----bean1----"+bean1);
总代码
public class DigInAutowired {
public static void main(String[] args) throws Throwable {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 创建过程、依赖注入、初始化
beanFactory.registerSingleton("bean2",new Bean2());
beanFactory.registerSingleton("bean3",new Bean3());
// @Value
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// 设置解析 @Value 注解中的 ${} 表达式的解析器
beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders);
// 1.查找那些属性、方法加了@Autowired,这称为 InjectionMetadata
AutowiredAnnotationBeanPostProcessor postProcessor = new AutowiredAnnotationBeanPostProcessor();
postProcessor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1();
// System.out.println("前bean1:" + bean1);
// postProcessor.postProcessProperties(null,bean1,"bean1");
// System.out.println("后bean1:" + bean1);
//--------- 模拟postProcessProperties 调用过程-------
Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.
class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
findAutowiringMetadata.setAccessible(true);
InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata.invoke(postProcessor,"bean1",Bean1.class,null);
System.out.println(metadata);
// 2.调用 InjectionMetadata 来进行依赖注入,注入时按类型查找值
metadata.inject(bean1,"bean1",null);
System.out.println("----bean1----"+bean1);
// 3. 如何按照类型查找值
}
给 bean3 加上
@Autowired
注解
如何去Bean工厂里面按类型查找值
由于InjectionMetadata.inject(bean1, “bean1”, null)的源码调用链过长,摘出主要调用过程进行演示
//3.1 @Autowired加在成员变量上,InjectionMetatadata给Bean1注入Bean3的过程
Field bean3 = Bean1.class.getDeclaredField("bean3");
bean3.setAccessible(true);
// 将这个属性封装成一个DependencyDescriptor对象
DependencyDescriptor dd1 = new DependencyDescriptor(bean3,false);
// 再执行beanFactory的doResolveDependency
Bean3 bean3Value = (Bean3)beanFactory.doResolveDependency(dd1,null,null,null);
System.out.println("bean3:----"+bean3Value);
// 3.2 @Autowired加在方法上,InjectionMetatadata给Bean1注入Bean2的过程
Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(setBean2, 0), true);
Bean2 bean2Value = (Bean2) beanFactory.doResolveDependency(dd2, "bean2", null, null);
System.out.println("bean2:----"+bean2Value);
// 3.3 @Autowired加在方法上,方法参数为String类型,加了@Value,
// InjectionMetadata给Bean1注入环境变量JAVA_HOME属性的值
Method setJava_home = Bean1.class.getDeclaredMethod("setJava_home", String.class);
DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(setJava_home, 0), true);
String java_home = (String) beanFactory.doResolveDependency(dd3, null, null, null);
System.out.println("java_home:----"+java_home);