先来几个问题
- BeanFactoryPostProcessor是做什么
- BeanDefinitionRegistryPostProcessor是做什么
- BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor有什么区别
- 这几个接口的执行顺序是什么样的?
Spring容器中主要的4个阶段
- Bean注册阶段,此阶段会完成所有Bean的注册
- BeanFactory后置处理阶段
- 注册BeanPostProcessor
- Bean创建阶段,此阶段完成所有单例bean的注册和装载操作。
Bean注册阶段
spring中所有bean的注册都会在此阶段完成,按照规范,所有bean的注册必须在此阶段进行,其他阶段不要再进行bean的注册。
这个阶段spring为我们提供1个接口:BeanDefinitionRegistryPostProcessor,spring容器在这个阶段中会获取容器中所有类型为BeanDefinitionRegistryPostProcessor的bean,然后会调用他们的postProcessBeanDefinitionRegistry方法,源码如下,方法参数类型是BeanDefinitionRegistry,这个类型大家都比较熟悉,即bean定义注册器,内部提供了一些方法可以用来向容器中注册bean。
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
当容器中有多个BeanDefinitionRegistryPostProcessor的时候,可以通过下面任意一种方式来指定顺序
- 实现org.springframework.core.PriorityOrdered接口
- 实现org.springframework.core.Ordered接口
执行顺序:PriorityOrdered.getOrder() asc,Ordered.getOrder() asc
案例 BeanDefinitionRegistryPostProcessor的简单使用
// 我们向容器中注册一个String类型,值为MyBeanDefinitionRegistryPostProcessor的bean
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
BeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(String.class)
.addConstructorArgValue("MyBeanDefinitionRegistryPostProcessor")
.getBeanDefinition();
registry.registerBeanDefinition("spring", beanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
配置
@ComponentScan
@Configuration
public class MainConfig10 {
}
测试:
@Test
public void testRegister(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig10.class);
Object spring = context.getBean("spring");
System.out.println(spring);
}
运行结果:
MyBeanDefinitionRegistryPostProcessor
小结
BeanDefinitionRegistryPostProcessor有个非常重要的实现类:ConfigurationClassPostProcessor
这些注解都是这个类ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry解析的
@Configuration
@ComponentScan
@Import
@ImportResource
@PropertySource
BeanFactory后置处理阶段
到这个阶段的时候,spring容器已经完成了所有bean的注册,这个阶段中你可以对BeanFactory中的一些信息进行修改,比如修改阶段1中一些bean的定义信息,修改BeanFactory的一些配置等等,此阶段spring也提供了一个接口来进行扩展:BeanFactoryPostProcessor,接口中有个方法postProcessBeanFactory,spring会获取容器中所有BeanFactoryPostProcessor类型的bean,然后调用他们的postProcessBeanFactory,来看一下这个接口的源码:
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
当容器中有多个BeanFactoryPostProcessor的时候,可以通过下面任意一种方式来指定顺序:
- 实现org.springframework.core.PriorityOrdered接口
- 实现org.springframework.core.Ordered接口
执行顺序:PriorityOrdered.getOrder() asc,Ordered.getOrder() asc
案例
@Component
public class LessonModel {
private String name;
@Override
public String toString() {
return "LessonModel{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("准备修改lessonModel bean定义信息!");
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("lessonModel");
beanDefinition.getPropertyValues().add("name", "spring高手系列!");
}
}
@Configuration
@ComponentScan
public class MainConfig11 {
}
@Test
public void testRegister1(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig11.class);
Object spring = context.getBean("lessonModel");
System.out.println(spring);
}
LessonModel{name='spring高手系列!'}
这个接口的几个重要实现类
PropertySourcesPlaceholderConfigurer
PropertySourcesPlaceholderConfigurer#postProcessBeanFactory中来处理xml中属性中的${xxx},会对这种格式的进行解析处理为真正的值。
CustomScopeConfigurer
向容器中注册自定义的Scope对象,即注册自定义的作用域实现类,关于自定义的作用域,不了解的朋友,建议先看一下 : spring系列- bean的scope
EventListenerMethodProcessor
处理@EventListener注解的,即spring中事件机制,需要了解spring事件的:spring系列- 事件机制
使用注意
BeanFactoryPostProcessor接口的使用有一个需要注意的地方,在其postProcessBeanFactory方法中,强烈禁止去通过容器获取其他bean,此时会导致bean的提前初始化,会出现一些意想不到的问题,因为这个阶段中BeanPostProcessor还未准备好,本文开头4个阶段中有介绍,BeanPostProcessor是在第3个阶段中注册到spring容器的,而BeanPostProcessor可以对bean的创建过程进行干预,比如spring中的aop就是在BeanPostProcessor的一些子类中实现的,@Autowired也是在BeanPostProcessor的子类中处理的,此时如果去获取bean,此时bean不会被BeanPostProcessor处理,所以创建的bean可能是有问题的,还是通过一个案例给大家演示一下把,通透一些。
案例
public class UserModel {
@Autowired
private String name;
@Override
public String toString() {
return "UserModel{" +
"name='" + name + '\'' +
'}';
}
}
@Configuration
@ComponentScan
public class MainConfig12 {
@Bean
public UserModel user1() {
return new UserModel();
}
@Bean
public UserModel user2() {
return new UserModel();
}
@Bean
public String name(){
return "spring";
}
}
@Component
public class UserModelProcess implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.getBean("user1");
}
}
@Test
public void testBeanPostProcessor(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig12.class);
context.getBeansOfType(UserModel.class).forEach((beanName, bean) -> {
System.out.println(String.format("%s->%s", beanName, bean));
});
}
user1->UserModel{name='null'}
user2->UserModel{name='spring'}
注意,user1中的name变成null了,什么情况?
是因为@Autowired注解是在AutowiredAnnotationBeanPostProcessor中解析的,spring容器调用BeanFactoryPostProcessor#postProcessBeanFactory的使用,此时spring容器中还没有AutowiredAnnotationBeanPostProcessor,所以此时去获取user1这个bean的时候,@Autowired并不会被处理,所以name是null。
源码:
org.springframework.context.support.AbstractApplicationContext#refresh
// 对应阶段1和阶段2:调用上下文中注册为bean的工厂处理器,即调用本文介绍的2个接口中的方法
invokeBeanFactoryPostProcessors(beanFactory);
// 对应阶段3:注册拦截bean创建的bean处理器,即注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 对应阶段3:实例化所有剩余的(非延迟初始化)单例。
finishBeanFactoryInitialization(beanFactory);
总结
- BeanDefinitionRegistryPostProcessor会在第一个阶段被调用,用来实现bean的注册操作,这个阶段会完成所有bean的注册
- BeanFactoryPostProcessor会在第2个阶段被调用,到这个阶段时候,bean此时已经完成了所有bean的注册操作,这个阶段中你可以对BeanFactory中的一些信息进行修改,比如修改阶段1中一些bean的定义信息,修改BeanFactory的一些配置等等
- 阶段2的时候,2个禁止操作:禁止注册bean、禁止从容器中获取bean
- 本文介绍的2个接口的实现类可以通过PriorityOrdered接口或者Ordered接口来指定顺序