Spring中BeanFactoryPostProcessor接口 -【Spring底层原理】

快来打我* 2021-09-21 21:06 390阅读 0赞

目录

一、概述

二、实例分析

三、源码分析

四、总结


一、概述

BeanFactoryPostProcessor是实现spring容器功能扩展的重要接口,例如修改bean属性值,实现bean动态代理等。很多框架都是通过此接口实现对spring容器的扩展,例如mybatis与spring集成时,只定义了mapper接口,无实现类,但spring却可以完成自动注入,这些都是如何实现的呢,本文将一探究竟。

区分:

  • BeanPostProcessor:bean后置处理器,bean创建对象初始化前后进行拦截工作的
  • BeanFactoryPostProcessor:beanFactory后置处理器,在beanFactory标准初始化之后调用,此时所有的bean定义已经保存加载到beanFactory中,但bean的实例还未创建,此时可以对bean的属性进行修改拓展

二、实例分析

  1. // 启动类
  2. @Test
  3. public void TestMain() {
  4. // 创建IOC容器
  5. new AnnotationConfigApplicationContext(AppConfig.class);
  6. }
  7. // 待注入的bean
  8. public class User {
  9. public User(){
  10. System.out.println("user create");
  11. }
  12. }
  13. // 配置类
  14. @ComponentScan("config")
  15. @Configuration
  16. public class AppConfig {
  17. @Bean
  18. public User user(){
  19. return new User();
  20. }
  21. }
  22. // BeanFactoryPostProcessor实现类
  23. @Component
  24. public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
  25. public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
  26. System.out.println("MyBeanFactoryPostProcessor#postProcessBeanFactory");
  27. int count = configurableListableBeanFactory.getBeanDefinitionCount();
  28. String[] names = configurableListableBeanFactory.getBeanDefinitionNames();
  29. System.out.println("当前BeanFactory中有" + count + "个Bean");
  30. System.out.println(Arrays.asList(names));
  31. }
  32. }

运行启动类,可以看到,通过获取到容器中的组件,发现在bean创建之前,就执行了MyBeanFactoryPostProcessor的postProcessBeanFactory方法,由此可以看出,在bean的实例还未创建的时候,也就是初始化之前,就会调用BeanFactoryPostProcessor,因此,可以在这里进行功能的拓展,修改bean的属性。

三、源码分析

具体是如何调用的,我们通过源码进行分析,使用Debug的方式来一步一步查看方法调用链,在postProcessBeanFactory方法的位置打上断点,Debug运行启动类:

可以看到,进入了refresh()方法的invokeBeanFactoryPostProcessors方法,也就是说,在invokeBeanFactoryPostProcessors方法中就执行了beanFactory的后置处理器方法。

image-20210317192535369

  1. public void refresh() throws BeansException, IllegalStateException {
  2. synchronized(this.startupShutdownMonitor) {
  3. ......
  4. // 在这个方法执行了beanFactory的后置处理器
  5. this.invokeBeanFactoryPostProcessors(beanFactory);
  6. ......
  7. }
  8. }

进入到下一个方法,到invokeBeanFactoryPostProcessors#invokeBeanFactoryPostProcessors方法,

  1. public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
  2. ......
  3. sortPostProcessors(regularPostProcessors, beanFactory);
  4. // 先执行实现了PriorityOrdered接口的PostProcessor(实现优先级接口的)
  5. invokeBeanFactoryPostProcessors((Collection)regularPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
  6. List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList(registryProcessors.size());
  7. Iterator var21 = registryProcessors.iterator();
  8. while(var21.hasNext()) {
  9. String postProcessorName = (String)var21.next();
  10. orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
  11. }
  12. sortPostProcessors(orderedPostProcessors, beanFactory);
  13. // 再执行实现了Ordered接口的PostProcessor
  14. invokeBeanFactoryPostProcessors((Collection)orderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
  15. List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList(currentRegistryProcessors.size());
  16. Iterator var24 = currentRegistryProcessors.iterator();
  17. while(var24.hasNext()) {
  18. ppName = (String)var24.next();
  19. // 从bean工厂中获取BeanFactoryPostProcessor,得到每一个PostProcessor的名字
  20. nonOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
  21. }
  22. // 执行beanFactory后置处理器(最后执行普通接口的PostProcessor)
  23. invokeBeanFactoryPostProcessors((Collection)nonOrderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
  24. beanFactory.clearMetadataCache();
  25. }

可以看到,在这个方法里面,是调用最下面的invokeBeanFactoryPostProcessors方法执行beanFactory后置处理器的,提出疑问:

我们是如何找到PostProcessor并执行他们的方法呢?

【1】获取PostProcessor

上面代码分别执行了三种接口的BeanFactoryPostProcessors,在执行之前,会对PostProcessor进行处理,如下,将三种PostProcessor分开放置:

  • priorityOrderedPostProcessors:放置有优先级排序的接口
  • orderedPostProcessorNames:放置有排序的PostProcessorNames
  • nonOrderedPostProcessorNames:放置普通的PostProcessorNames

    public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

    1. ......
    2. for(int var10 = 0; var10 < var9; ++var10) {
    3. ppName = var8[var10];
    4. // 将有优先级排序接口的放到priorityOrderedPostProcessors
    5. if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    6. pp = (BeanPostProcessor)beanFactory.getBean(ppName, BeanPostProcessor.class);
    7. priorityOrderedPostProcessors.add(pp);
    8. if (pp instanceof MergedBeanDefinitionPostProcessor) {
    9. internalPostProcessors.add(pp);
    10. }
    11. // 将有排序接口的放到orderedPostProcessorNames
    12. } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
    13. orderedPostProcessorNames.add(ppName);
    14. } else {
    15. // 将普通接口的放到nonOrderedPostProcessorNames
    16. nonOrderedPostProcessorNames.add(ppName);
    17. }
    18. }
    19. ......

    }

这里百便获取到了相应的PostProcessor,有PriorityOrdered接口的,有Ordered接口的,也有普通接口的 ,之后,进行遍历,我们实现的是普通接口的,从bean工厂中获取BeanFactoryPostProcessor,得到每一个PostProcessor的名字

【2】遍历执行PostProcessor

  1. private static void invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
  2. Iterator var2 = postProcessors.iterator();
  3. while(var2.hasNext()) {
  4. BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var2.next();
  5. StartupStep var10000 = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process");
  6. postProcessor.getClass();
  7. StartupStep postProcessBeanFactory = var10000.tag("postProcessor", postProcessor::toString);
  8. postProcessor.postProcessBeanFactory(beanFactory);
  9. postProcessBeanFactory.end();
  10. }
  11. }

遍历出每个PostProcessor,回调每一个的postProcessBeanFactory方法。

四、总结

  1. refresh():IOC容器创建对象
  2. invokeBeanFactoryPostProcessors():执行BeanFactoryPostProcessors,即beanFactory的后置处理器

    1. 直接在BeanFactory中找到所有类型是BeanFactoryPostProcessors的组件,并执行他们的方法
    2. 通过源码可以看到,是在初始化其他组件(finishBeanFactoryInitialization)之前执行的

发表评论

表情:
评论列表 (有 0 条评论,390人围观)

还没有评论,来说两句吧...

相关阅读