20.spring系列- BeanFactory扩展

先来几个问题

  1. BeanFactoryPostProcessor是做什么
  2. BeanDefinitionRegistryPostProcessor是做什么
  3. BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor有什么区别
  4. 这几个接口的执行顺序是什么样的?

Spring容器中主要的4个阶段

  1. Bean注册阶段,此阶段会完成所有Bean的注册
  2. BeanFactory后置处理阶段
  3. 注册BeanPostProcessor
  4. 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的时候,可以通过下面任意一种方式来指定顺序

  1. 实现org.springframework.core.PriorityOrdered接口
  2. 实现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的时候,可以通过下面任意一种方式来指定顺序:

  1. 实现org.springframework.core.PriorityOrdered接口
  2. 实现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);

总结

  1. BeanDefinitionRegistryPostProcessor会在第一个阶段被调用,用来实现bean的注册操作,这个阶段会完成所有bean的注册
  2. BeanFactoryPostProcessor会在第2个阶段被调用,到这个阶段时候,bean此时已经完成了所有bean的注册操作,这个阶段中你可以对BeanFactory中的一些信息进行修改,比如修改阶段1中一些bean的定义信息,修改BeanFactory的一些配置等等
  3. 阶段2的时候,2个禁止操作:禁止注册bean、禁止从容器中获取bean
  4. 本文介绍的2个接口的实现类可以通过PriorityOrdered接口或者Ordered接口来指定顺序
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值