Bean 后处理器
后处理器作用
-
@Autowired 等注解的解析属于 bean 生命周期阶段(依赖注入, 初始化)的扩展功能,这些扩展功能由 bean 后处理器来完成
-
每个后处理器各自增强什么功能
-
AutowiredAnnotationBeanPostProcessor 解析 @Autowired 与 @Value
-
CommonAnnotationBeanPostProcessor 解析 @Resource、@PostConstruct、@PreDestroy
-
ConfigurationPropertiesBindingPostProcessor 解析 @ConfigurationProperties
-
-
另外 ContextAnnotationAutowireCandidateResolver 负责获取 @Value 的值,解析 @Qualifier、泛型、@Lazy 等
为了演示各个bean后处理器的作用,首先我们需要创建bean对象
bean1(其中通过setter方法注入了bean2以及bean3,还注入了一个成员变量)
public class Bean1 {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
private Bean2 bean2;
@Autowired
public void setBean2(Bean2 bean2) {
log.debug("@Autowired 生效: {}", bean2);
this.bean2 = bean2;
}
@Autowired
private Bean3 bean3;
@Resource
public void setBean3(Bean3 bean3) {
log.debug("@Resource 生效: {}", bean3);
this.bean3 = bean3;
}
private String home;
@Autowired
public void setHome(@Value("${JAVA_HOME}") String home) {
log.debug("@Value 生效: {}", home);
this.home = home;
}
bean2
public class Bean2 {
}
bean3
public class Bean3 {
}
现在我们可以创建容器并把这些bean对象注册到容器当中,初始化容器时执行beanFactory后处理器, 添加bean后处理器, 初始化所有单例,关闭容器时可以看到bean对象的销毁阶段
public class Spring04Application {
public static void main(String[] args) {
//比较干净的容器,没有默认的bean后处理器
GenericApplicationContext context = new GenericApplicationContext();
//注册bean
context.registerBean("bean1", Bean1.class);
context.registerBean("bean2", Bean2.class);
context.registerBean("bean3", Bean3.class);
//初始化容器
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
context.close();
}
}
此时我们可以看到容器内部只添加了我们手动注册的bean对象,依赖注入的对象以及成员变量并没有被解析
由于是比较干净的容器,容器内部并没有默认的bean的后处理器,我们可以逐一添加bean的后处理器观察结果(添加AutowiredAnnotationBeanPostProcessor后处理器可以解析autowired,value注解)
public class Spring04Application {
public static void main(String[] args) {
//比较干净的容器,没有默认的bean后处理器
GenericApplicationContext context = new GenericApplicationContext();
//注册bean
context.registerBean("bean1", Bean1.class);
context.registerBean("bean2", Bean2.class);
context.registerBean("bean3", Bean3.class);
//添加到beanfactory,交给容器管理
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
context.registerBean(AutowiredAnnotationBeanPostProcessor.class); //autowired value注解
//初始化容器
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
context.close();
}
}
此时我们可以发现容器内部多出了我们添加的bean后处理器以及@value,@autowired注解也被成功解析
我们可以再往容器内部添加 CommonAnnotationBeanPostProcessor后处理器(可以解析@Resource @PostConstruct @PreDestroy注解)
public class Spring04Application {
public static void main(String[] args) {
//比较干净的容器,没有默认的bean后处理器
GenericApplicationContext context = new GenericApplicationContext();
//注册bean
context.registerBean("bean1", Bean1.class);
context.registerBean("bean2", Bean2.class);
context.registerBean("bean3", Bean3.class);
//添加到beanfactory,交给容器管理
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
context.registerBean(AutowiredAnnotationBeanPostProcessor.class); //autowired value注解
context.registerBean(CommonAnnotationBeanPostProcessor.class); // @Resource @PostConstruct @PreDestroy
//初始化容器
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
context.close();
}
}
可以观察到容器内部多出了一个新的后处理器,以及上述三个注解都生效了
还有一个注解@ConfigurationProperties,接下来我们来创建该类(指定了配置类属性的前缀名,以及在这个类中利用setter注入两个成员变量,并重写了该类的tostring方法)
@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 + '\'' +
'}';
}
}
创建了配置类,由于是普通的java项目,我们需要手动在启动类上开启配置类注解并扫描到该类
@EnableConfigurationProperties(value = {Bean4.class})
把bean4对象注册到容器中,由于重写了tostring方法,只需要获取到该类的bean对象并打印就可看到成员变量是否被成功注入
@EnableConfigurationProperties(value = {Bean4.class})
public class Spring04Application {
public static void main(String[] args) {
//比较干净的容器,没有默认的bean后处理器
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);
//添加到beanfactory,交给容器管理
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
context.registerBean(AutowiredAnnotationBeanPostProcessor.class); //autowired value注解
context.registerBean(CommonAnnotationBeanPostProcessor.class); // @Resource @PostConstruct @PreDestroy
//初始化容器
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean4.class));
context.close();
}
}
可以看到容器内部只多出了我们手动注册的对象,成员变量为空值
添加解析 @ConfigurationProperties注解的后处理器,它和前两种方式有所不同(通过ConfigurationPropertiesBindingPostProcessor配置属性类绑定后处理器)
@EnableConfigurationProperties(value = {Bean4.class})
public class Spring04Application {
public static void main(String[] args) {
//比较干净的容器,没有默认的bean后处理器
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);
//添加到beanfactory,交给容器管理
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
context.registerBean(AutowiredAnnotationBeanPostProcessor.class); //autowired value注解
context.registerBean(CommonAnnotationBeanPostProcessor.class); // @Resource @PostConstruct @PreDestroy
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
//初始化容器
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean4.class));
context.close();
}
}
可以发现容器内部多出了三个bean的后处理器,以及成员变量也被成功注入
学到了什么
a. @Autowired 等注解的解析属于 bean 生命周期阶段(依赖注入, 初始化)的扩展功能
b. 这些扩展功能由 bean 后处理器来完成
@Autowired bean 后处理器运行分析
// AutowiredAnnotationBeanPostProcessor 运行分析
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());
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); // @Value
beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders); // ${} 的解析器
// 1. 查找哪些属性、方法加了 @Autowired, 这称之为 InjectionMetadata
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1();
// System.out.println(bean1);
// processor.postProcessProperties(null, bean1, "bean1"); // 执行依赖注入 @Autowired @Value
// System.out.println(bean1);
// Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
// findAutowiringMetadata.setAccessible(true);
// InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor, "bean1", Bean1.class, null);// 获取 Bean1 上加了 @Value @Autowired 的成员变量,方法参数信息
// System.out.println(metadata);
// 2. 调用 InjectionMetadata 来进行依赖注入, 注入时按类型查找值
// metadata.inject(bean1, "bean1", null);
// System.out.println(bean1);
// 3. 如何按类型查找值
Field bean3 = Bean1.class.getDeclaredField("bean3");
DependencyDescriptor dd1 = new DependencyDescriptor(bean3, false);
Object o = beanFactory.doResolveDependency(dd1, null, null, null);
System.out.println(o);
Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
DependencyDescriptor dd2 =
new DependencyDescriptor(new MethodParameter(setBean2, 0), true);
Object o1 = beanFactory.doResolveDependency(dd2, null, null, null);
System.out.println(o1);
Method setHome = Bean1.class.getDeclaredMethod("setHome", String.class);
DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(setHome, 0), true);
Object o2 = beanFactory.doResolveDependency(dd3, null, null, null);
System.out.println(o2);
}
}
1. 查找哪些属性、方法加了 @Autowired, 这称之为 InjectionMetadata
首先我们实例化一个后处理器AutowiredAnnotationBeanPostProcessor对象并与该beanfactory进行绑定,添加到容器中,该处理器会去 查找哪些属性、方法加了 @Autowired,查找到的类统一称为 InjectionMetadata
其次把bean1对象依赖注入到容器当中,观察其他类或属性是否成功注入
此时可以看到注入成功
然后我们可以使用方法findAutowiringMetadata,默认该方法是不能查找到bean对象的,把他设置成true,通过该方法获取 Bean1 上加了 @Value @Autowired 的成员变量,方法参数信息
2. 调用 InjectionMetadata 来进行依赖注入, 注入时按类型查找值
我们可以通过获取到的InjectionMetadata对象调用它的inject方法来注入
可以发现也能成功注入
3. 如何按类型查找值
// AutowiredAnnotationBeanPostProcessor 运行分析
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());
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); // @Value
beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders); // ${} 的解析器
// 1. 查找哪些属性、方法加了 @Autowired, 这称之为 InjectionMetadata
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1();
// System.out.println(bean1);
// processor.postProcessProperties(null, bean1, "bean1"); // 执行依赖注入 @Autowired @Value
// System.out.println(bean1);
// Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
// findAutowiringMetadata.setAccessible(true);
// InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor, "bean1", Bean1.class, null);// 获取 Bean1 上加了 @Value @Autowired 的成员变量,方法参数信息
// System.out.println(metadata);
// 2. 调用 InjectionMetadata 来进行依赖注入, 注入时按类型查找值
// metadata.inject(bean1, "bean1", null);
// System.out.println(bean1);
// 3. 如何按类型查找值
Field bean3 = Bean1.class.getDeclaredField("bean3");
DependencyDescriptor dd1 = new DependencyDescriptor(bean3, false);
Object o = beanFactory.doResolveDependency(dd1, null, null, null);
System.out.println(o);
Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
DependencyDescriptor dd2 =
new DependencyDescriptor(new MethodParameter(setBean2, 0), true);
Object o1 = beanFactory.doResolveDependency(dd2, null, null, null);
System.out.println(o1);
Method setHome = Bean1.class.getDeclaredMethod("setHome", String.class);
DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(setHome, 0), true);
Object o2 = beanFactory.doResolveDependency(dd3, null, null, null);
System.out.println(o2);
}
}
首先通过bean1的字节码反射获取到它的成员变量和成员方法
其通过获取到的方法与方法获取到DependencyDescriptor对象
调用beanFactory的doResolveDependency方法就可以获取到注入的值或对象