Springboot扩展点之BeanFactoryPostProcessor


You
You 2024-01-08 23:48:06 50012 赞同 0 反对 0
分类: 资源
功能特性 BeanFactoryPostProcessor的执行是Spring Bean生命周期非常重要的一部分; BeanFactory级别的后置处理器,在Spring生命周期内,org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory只会执行一次; 允许在容器读取到Bean的BeanDefinition数据之后,bean未实例化前,读取BeanDefiniion数据,并且可以根据需要进行修改;

功能特性

  • BeanFactoryPostProcessor的执行是Spring Bean生命周期非常重要的一部分;
  • BeanFactory级别的后置处理器,在Spring生命周期内,org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory只会执行一次;
  • 允许在容器读取到Bean的BeanDefinition数据之后,bean未实例化前,读取BeanDefiniion数据,并且可以根据需要进行修改;

实现方式

1、定义一个Dog类,name属性默认为“旺财”,颜色默认为“黑色”;

@Data
@Component
public class Dog {
    private String name="旺财";
    private String color="黑色";
}

2、定义一个实现类(MyBeanFactoryPostProcessor),实现BeanFactoryPostProcessor接口,重写postProcessBeanFactory()方法,并Dog类的属性name修改为“狗蛋”;并用@Component注解标记BeanFactoryPostProcessor接口的实现类(MyBeanFactoryPostProcessor)

@Component
@Slf4j
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        log.info("com.fanfu.config.MyBeanFactoryPostProcessor.postProcessBeanFactory被执行");
        ScannedGenericBeanDefinition dog = ((ScannedGenericBeanDefinition) beanFactory.getBeanDefinition("dog"))  ;
        MutablePropertyValues propertyValues = dog.getPropertyValues();
        propertyValues.addPropertyValue("name", "狗蛋儿");
        log.info("修改Dog的BeanDefinition对象中的name属性为狗蛋儿");
    }
}

3、编写单元测试验证结果

@SpringBootTest
@Slf4j
public class FanfuApplicationTests {
    @Test
    public void test(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.fanfu");
        Dog dog = ((Dog) context.getBean("dog"));
        log.info(dog.getName());
        Assert.isTrue(dog.getName().equals("狗蛋儿"), "属性修改失败");
    }
}

4、验证结果表明,自定义的BeanFactoryPostProcessor接口的实现类(MyBeanFactoryPostProcessor),可以在容器读取到Bean的BeanDefinition数据之后,bean未实例化前,读取BeanDefiniion数据,并且根据需要进行修改,那么自定义的BeanFactoryPostProcessor接口的实现类(MyBeanFactoryPostProcessor)的工作原理是什么呢?BeanFactoryPostProcessor接口的实现类是什么时候实例化的?MyBeanFactoryPostProcessor#postProcessBeanFactory方法是如何被调用的?接着往下看。

工作原理

BeanFactoryPostProcessor接口的实现类是什么时候实例化的?

1、BeanFactoryPostProcessor接口的实现类(MyBeanFactoryPostProcessor)被@Component标记,在窗口启动的时候会被封装成BeanDefinition对象注册到容器中;

图片图片

2、PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法被执行时,会按照类型从Spring容器中找到所有BeanFactoryPostProcessor类型的实现类的名称;

图片图片

3、在上一步中得到所有BeanFactoryPostProcessor类型的实现类的名称的名称后,再循环一次,来对BeanFactoryPostProcessor的实现类进行实例化 (beanFacotry.getBean()去获取MyBeanFactoryPostProcessor的实例,如果获取不到,就创建一个);

图片图片

MyBeanFactoryPostProcessor#postProcessBeanFactory方法是如何被调用的?

1、在单元测试中构建了一个AnnotationConfigApplicationContext对象,AnnotationConfigApplicationContext的构造方法如下:

public AnnotationConfigApplicationContext(String… basePackages) {   this();   scan(basePackages);   refresh(); }

2、从上面的AnnotationConfigApplicationContext的构造方法中,可以看到又调用了refresh(),这里实际最终被调用的是AbstractApplicationContext#refresh(),这个方法也是Spring容器启动的关键方法,在分析Spring相关的源码时会经常碰到。

3、AbstractApplicationContext#refresh()中,调用AbstractApplicationContext#invokeBeanFactoryPostProcessors方法才正式开始了BeanFactoryPostProcessor接口的所有实现类的postProcessBeanFactory()方法调用;

4、跟着AbstractApplicationContext#invokeBeanFactoryPostProcessors方法进去,会发现这里只是一个入口,实际承担调用执行任务的是PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法;

5、跟着PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法进去后,会发现里面真的是别有洞天,很容易迷路(牢牢带着自己的问题分析源码找答案,不要被除自己问题以外的东西迷了眼,一定会柳暗花明),另外org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor的实现类的调用也在这个方法,所以这个方法的含金量很高,那就单独拎出来仔细分析一下,建议debug一步一步看,多看几遍就能明白,其实也很简单,唯一的难点就是这个方法有点长,需要多点耐心和时间。

public static void invokeBeanFactoryPostProcessors(
      ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) {
   //之所以说这个方法的含金量很高,
   //是因为在这个方法里是先执行BeanDefinitionRegistryPostProcessor实现类的postProcessBeanDefinitionRegistry方法;//然后才接着执行BeanFactoryPostProcessor接口的实现类的postProcessBeanFactory方法
   //这两个接口很表面上看很类似,实际在执行的时机和功能上是有明显区别的
   Set processedBeans = new HashSet();
   //AnnotationConfigApplicationContext继承于GenericApplicationContext,
   //而GenericApplicationContext又实现了BeanDefinitionRegistry接口
   //所以这里会进入if语句中
   if (beanFactory instanceof BeanDefinitionRegistry) {
      BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
      List regularPostProcessors = new ArrayList();
      List registryProcessors = new ArrayList();
        //这里提前执行的BeanFactoryPostProcessor,是在准备上下文环境时,发布了ApplicationPreparedEvent事件;//触发监听器,通过AbstractApplicationContext#addBeanFactoryPostProcessor注册进来的;//这里并不是这次要重点分析的内容,可以先跳过这;for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
         if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
            BeanDefinitionRegistryPostProcessor registryProcessor =
                  (BeanDefinitionRegistryPostProcessor) postProcessor;
            registryProcessor.postProcessBeanDefinitionRegistry(registry);
            registryProcessors.add(registryProcessor);
         }
         else {
            regularPostProcessors.add(postProcessor);
         }
      }
      List currentRegistryProcessors = new ArrayList();
      // 从32行到72行,是在执行BeanDefinitionRegistryPostProcessor实现类的postProcessBeanDefinitionRegistry方法;//执行的过程也是有点小区折的,分三步,第一,执行实现了PriorityOrdered接口的实现类.
      String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
      for (String ppName : postProcessorNames) {
         if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
            processedBeans.add(ppName);
         }
      }
      sortPostProcessors(currentRegistryProcessors, beanFactory);
      registryProcessors.addAll(currentRegistryProcessors);
      invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
      currentRegistryProcessors.clear();
      // 第二,执行实现了Ordered接口的实现类;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
      for (String ppName : postProcessorNames) {
         if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
            currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
            processedBeans.add(ppName);
         }
      }
      sortPostProcessors(currentRegistryProcessors, beanFactory);
      registryProcessors.addAll(currentRegistryProcessors);
      invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
      currentRegistryProcessors.clear();
      //第三,执行剩下其他的BeanDefinitionRegistryPostProcessor实现类;boolean reiterate = true;
      while (reiterate) {
         reiterate = false;
         postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
         for (String ppName : postProcessorNames) {
            if (!processedBeans.contains(ppName)) {
               currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
               processedBeans.add(ppName);
               reiterate = true;
            }
         }
         sortPostProcessors(currentRegistryProcessors, beanFactory);
         registryProcessors.addAll(currentRegistryProcessors);
         invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
         currentRegistryProcessors.clear();
      }
      // BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor,
      //所以这部分实现类的postProcessBeanFactory()会提前执行
      invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
      //第26行,非BeanDefinitionRegistryPostProcessor类型的BeanFactoryPostProcessor实现类会在这执行
      invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
   } else {
      invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
   }
   //BeanDefinitionRegistryPostProcessor接口的实现类上面已执行执行完了
   //下面开始准备执行BeanFactoryPostProcessor接口的实现类
   String[] postProcessorNames =
         beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
   // 正式执行前,把BeanFactoryPostProcessor接口的实现类分成了三类,
   //分别是实现了PriorityOrdered接口,实现了Ordered接口,其他;
   List priorityOrderedPostProcessors = new ArrayList();
   List orderedPostProcessorNames = new ArrayList();
   List nonOrderedPostProcessorNames = new ArrayList();
   for (String ppName : postProcessorNames) {
      if (processedBeans.contains(ppName)) {
         // skip - already processed in first phase above
      }
      else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
         priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
      }
      else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
         orderedPostProcessorNames.add(ppName);
      }
      else {
         nonOrderedPostProcessorNames.add(ppName);
      }
   }
   // 分好类,第一,先执行实现了PriorityOrdered接口的实现类;sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
   invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
   // 第二,执行实现了Ordered接口的实现类;List orderedPostProcessors = new ArrayList(orderedPostProcessorNames.size());
   for (String postProcessorName : orderedPostProcessorNames) {
      orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
   }
   sortPostProcessors(orderedPostProcessors, beanFactory);
   invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
   //第三,执行未实现上面两个接口的实现类,自定义的MyBeanFactoryPostProcessor就是在这里被执行的
   //其实,也很简单的,和BeanDefinitionRegistryPostProcessor接口的实现类的执行过程类似;List nonOrderedPostProcessors = new ArrayList(nonOrderedPostProcessorNames.size());
   for (String postProcessorName : nonOrderedPostProcessorNames) {
      nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
   }
   invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
   beanFactory.clearMetadataCache();
}

调用时序图

这里我画了一个时序图,可以更直观的看到整个调用过程,也可以照着这个图,一步一步debug来了解整个过程;

图片图片

postProcessBeanFactory()与postProcessBeanDefinitionRegistry()

通过分析PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法,postProcessBeanFactory()与postProcessBeanDefinitionRegistry()的区别已经很明显了,这里再总结一下(总结的有不准的地方,还请小伙伴在评论区告诉我,一块进步):

  • BeanDefinitionRegistryPostProcessor接口的实现类的postProcessBeanDefinitionRegistry方法要优先于BeanFactoryPostProcessor接口的实现类的postProcessBeanFactory方法执行;
  • postProcessBeanDefinitionRegistry方法形参是BeanDefinitionRegistry,postProcessBeanFactory方法的形参是ConfigurableListableBeanFactory,在功能上会有一些区别;需要注意的是DefaultListableBeanFactory实现了BeanDefinitionRegistry和ConfigurableListableBeanFactory接口;
  • BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor,关于BeanDefinitionRegistryPostProcessor可以移步这里:Springboot扩展点之BeanDefinitionRegistryPostProcessor;

应用场景

对敏感信息的解密处理,比如数据库连接信息加密和解密:在实际的业务开发中,在配置文件中明文配置mysq,redis的密码实际上是不安全的,需要配置加密后的密码信息;但是把加密后的密码信息注入的数据源中,去连接mysql数据库肯定会连接异常,因为mysql并不知道你的加密方式和加密方法。这就会产生一个需求:需要在配置文件中配置的数据库信息是加密的,但是在把密码信息注入数据源前在程序里解密处理。

BeanFactoryPostProcessor正好可以解决这个问题,在真正使用到数据源去连接数据库前,读取到加密信息,进行解密处理,再用解密后的信息替换掉Spring容器中加密信息。

如果您发现该资源为电子书等存在侵权的资源或对该资源描述不正确等,可点击“私信”按钮向作者进行反馈;如作者无回复可进行平台仲裁,我们会在第一时间进行处理!

评价 0 条
YouL0
粉丝 0 资源 386 + 关注 私信
最近热门资源
银河麒麟桌面操作系统备份用户数据  127
统信桌面专业版【全盘安装UOS系统】介绍  122
银河麒麟桌面操作系统安装佳能打印机驱动方法  114
银河麒麟桌面操作系统 V10-SP1用户密码修改  105
最近下载排行榜
银河麒麟桌面操作系统备份用户数据 0
统信桌面专业版【全盘安装UOS系统】介绍 0
银河麒麟桌面操作系统安装佳能打印机驱动方法 0
银河麒麟桌面操作系统 V10-SP1用户密码修改 0
作者收入月榜
1

prtyaa 收益393.62元

2

zlj141319 收益218元

3

1843880570 收益214.2元

4

IT-feng 收益209.03元

5

风晓 收益208.24元

6

777 收益172.71元

7

Fhawking 收益106.6元

8

信创来了 收益105.84元

9

克里斯蒂亚诺诺 收益91.08元

10

技术-小陈 收益79.5元

请使用微信扫码

加入交流群

请使用微信扫一扫!