例子:后置处理器解析各个注解
public class Bean2 {
}
public class Bean3 {
}
/**
* @author 我见青山多妩媚
* @date Create on 2022/9/30 17:17
*/
@Slf4j
public class Bean1 {
private Bean2 bean2;
@Autowired
public void setBean2(Bean2 bean2) {
log.info("@Autowired生效:{}",bean2);
this.bean2 = bean2;
}
private Bean3 bean3;
@Resource
public void setBean3(Bean3 bean3) {
log.info("@Resource生效:{}",bean3);
this.bean3 = bean3;
}
private String home;
@Autowired
private void setHome(@Value("${JAVA_HOME}") String home){
log.info("@Value生效:{}",home);
}
@PostConstruct
public void init(){
log.info("@PostConstruct生效");
}
@PreDestroy
public void destroy(){
log.info("@PreDestroy生效");
}
}
public class A04Application {
public static void main(String[] args) {
//是一个【干净】的容器,因为里面没有添加后处理器
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(Bean1.class);
context.registerBean(Bean2.class);
context.registerBean(Bean3.class);
//初始化容器,执行bean后处理器,添加beanFactory后处理器,初始化所有单例
context.refresh();
context.close();
}
}
我们先启动一次,看看里面都加载了什么
里面就创建了三个bean对象
我们依次添加后处理器,查看后面解析的内容
@Autowired
解析,在创建bean3后添加 //添加后置处理器解析,不加的话只有上面的注册bean,实际上bean1内的注解都没解析出来
//1.解析@Autowired 和 @Value,如果使用默认的AutowireCandidateResolver,@Value的值注入无法被解析,会报错,所以这里重新设置他的解析
//依赖注入阶段解析
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
运行结果:
此时解析的内容挺多的,两个注解都解析了,但是还有一个部分没有解析,我们接着往上添加
//2.解析@Resource(依赖注入解析) 和 @PostConstruct(初始化前解析) @PreDestroy(销毁前)
context.registerBean(CommonAnnotationBeanPostProcessor.class);
运行结果:
注解全部解析,至于为什么@Resource
比@Autowired
先解析,上面已经提到过,不再赘述
@ConfigurationProperties解析
package com.spring.demo.demo04;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author 我见青山多妩媚
* @date Create on 2022/10/3 11:22
*/
//匹配配置文件中的键值信息,以java开头
@ConfigurationProperties(prefix = "java")
public class Bean4 {
private String home;
private String version;
public String getHome() {
return home;
}
public void setHome(String home) {
this.home = home;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
@Override
public String toString() {
return "Bean4{" +
"home='" + home + '\'' +
", version='" + version + '\'' +
'}';
}
}
//3.解析@ConfigurationProperties,初始化前解析
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
System.out.println(context.getBean(Bean4.class));
运行结果:
Bean4{home='E:\enviornment\java\IntelliJ IDEA 2020.1.2\jbr', version='11.0.7'}
处理解析
对Bean1添加toString()方法,添加测试类
//AutowiredAnnotationBeanPostProcessor 运行分析
public class DigInAutowired {
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 processor = new AutowiredAnnotationBeanPostProcessor();
processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1();
System.out.println(bean1);
//执行依赖注入,解析@Autowired
processor.postProcessProperties(null,bean1,"bean1");
System.out.println(bean1);
//2.调用InjectionMetadata 进行依赖注入,注入时按类型查找值
}
}
运行结果:
Bean1{bean2=null, bean3=null, home='null'}
20:26:55.398 [main] INFO com.spring.demo.demo04.Bean1 - @Value生效:${JAVA_HOME}
20:26:55.406 [main] INFO com.spring.demo.demo04.Bean1 - @Autowired生效:com.spring.demo.demo04.Bean2@5cdd8682
Bean1{bean2=com.spring.demo.demo04.Bean2@5cdd8682, bean3=null, home='null'}
可以看到,我们的结果是没问题的,解析了@Autowired的注解
另外,我们也可以得到哪些方法和参数上加了对应的注解
//2.调用InjectionMetadata 进行依赖注入,注入时按类型查找值
Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
findAutowiringMetadata.setAccessible(true);
//获取bean1上加了@Vaule和@Autowired的成员变量和方法参数
InjectionMetadata metadata =(InjectionMetadata) findAutowiringMetadata.invoke(processor, "bean1", Bean1.class, null);
System.out.println(metadata);
使用debug运行,运行结果:
找到方法或参数上的注解
//3.如何按类型查找值
Field bean3 = Bean1.class.getDeclaredField("bean3");
//封装,false-->如果bean3没有依赖注入,返回的是null,如果设为true,那么将抛异常
DependencyDescriptor d1 = new DependencyDescriptor(bean3, false);
Object o = beanFactory.doResolveDependency(d1, null, null, null);
System.out.println(o);
//加了注解的方法怎么找到
Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
DependencyDescriptor d2 = new DependencyDescriptor(new MethodParameter(setBean2, 0), false);
Object o1 = beanFactory.doResolveDependency(d2, null, null, null);
System.out.println(o1);
//值注入
Method setHome = Bean1.class.getDeclaredMethod("setHome", String.class);
//sethome 方法的第0个参数
DependencyDescriptor d3 = new DependencyDescriptor(new MethodParameter(setHome, 0), false);
Object o2 = beanFactory.doResolveDependency(d3, null, null, null);
System.out.println(o2);
运行结果:
com.spring.demo.demo04.Bean3@43d7741f
com.spring.demo.demo04.Bean2@69379752
${JAVA_HOME}