写点什么

Spring BeanPostProcessor 你不能不知道的事

用户头像
CoderLi
关注
发布于: 2020 年 06 月 17 日

相关文章


上一篇文章我们聊了下 ``Aware` 接口、今天我们再来聊一下 `BeanPostProcessor`` 吧


为了各位客官老爷们看代码方便、不贴代码了、直接截图





其实再 ``AbstractBeanFactory` 中有一个 `List` 专门存放着所有的 `BeanPostProcessor``


private final List<BeanPostProcessor> beanPostProcessors;
复制代码


我们先来一睹 ``BeanPostProcessor`` 的真容吧



就那么两个方法


我们写个小例子玩玩呗




运行 ``demo`` , 居然没有打印出来



看来我们需要手动注册一波


defaultListableBeanFactory.addBeanPostProcessor(new Student());
复制代码


我擦、这波操作有点骚啊、还真别这么写正常编码的时候。再次运行


Student:postProcessBeforeInitialization:studentStudent:postProcessAfterInitialization:student
复制代码


BeanFactory 就这么弱鸡吗 ? 记得 ``ApplicationContext`` 是不用我们去注册的


我们使用一下 ``ApplicationContext`` 吧那就



运行一波、但是我的填为啥还是没打印呢、我们看看发生了啥、



当创建好 ``bean` 然后回调 `BeanPostProcessor` 的时候、我们发现、在 `beanPostProcessors` 中并没有 `Student`` 这个对象、也就是没有加入注册进去



但是我们在 ``ApplicationContext`` 初始化之后查看、发现它又在了、这、究竟是怎么回事呢 ( 我怎么这么多屁话 )


我先把调用链给出来吧


ClassPathXmlApplicationContext构造函数-->refresh()-->registerBeanPostProcessors()
复制代码


``registerBeanPostProcessors`` 看其名就知道它是干啥的了、


registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {   PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);}
复制代码



代码有点长、我们一点点分析


String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
复制代码


这个代码就是先从已经注册的 ``beanDefinition` 中找到所有实现了 `BeanPostProcessor``beanName`、然后反手就注册一个叫做 `BeanPostProcessorChecker``BeanPostProcessor`` 。这个类有什么作用呢、下次一定跟大家一起学习一下、下次一定


List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>();
复制代码


然后就定义了四个局部变量存放 ``beanName` 或者 `BeanPostProcessor`` 对象


  • ``priorityOrderedPostProcessors` 这个是存放即实现了 `BeanPostProcessor` 又实现了 `PriorityOrdered`` 接口的

  • ``internalPostProcessors` 存放的实现了 `PriorityOrdered``MergedBeanDefinitionPostProcessor` 接口的( `MergedBeanDefinitionPostProcessor` 继承 `BeanPostProcessor` ),可以认为 `internalPostProcessors``priorityOrderedPostProcessors`` 的子集

  • ``orderedPostProcessorNames` 存放实现了 `Ordered`` 接口的

  • ``nonOrderedPostProcessorNames`` 捡漏上面都不是的


for (String ppName : postProcessorNames) {   if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {      BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);      priorityOrderedPostProcessors.add(pp);      if (pp instanceof MergedBeanDefinitionPostProcessor) {         internalPostProcessors.add(pp);      }   }   else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {      // 为啥不在这里调用 getBean 方法、而是在下面的 for 循环中再调用、      orderedPostProcessorNames.add(ppName);   }   else {      // 为啥不在这里调用 getBean 方法、而是在下面的 for 循环中再调用、      nonOrderedPostProcessorNames.add(ppName);   }}
复制代码


上面的代码就是遍历获取到的实现了 ``BeanPostProcessor` 接口的 `beanName`、如果它也实现了 `PriorityOrdered`` 接口的、那就调用 getBean 方法获取其 bean、如果只是实现了 Ordered 接口或者都没实现的话、那么就直接加入到对应的 List 中。这里留个问题,为啥保存实现 PriorityOrdered 接口的就要保存其 bean、实现 Ordered 或者都没实现的为啥只是保存其 beanName 、在上面的 else if 和 else 里面 getBean 一下不就得了 ?


// 先进行排序sortPostProcessors(priorityOrderedPostProcessors, beanFactory);// 注册registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
复制代码


这里就是对实现了 PriorityOrdered 接口的 先进行排序、优先级高的先注册


List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());for (String ppName : orderedPostProcessorNames) {   BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);   orderedPostProcessors.add(pp);   if (pp instanceof MergedBeanDefinitionPostProcessor) {      internalPostProcessors.add(pp);   }}sortPostProcessors(orderedPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now, register all regular BeanPostProcessors.List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());for (String ppName : nonOrderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); nonOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); }}registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
复制代码


上面的这些代码都是差不多了的、都是能排序的话就先排序、然后再注册


sortPostProcessors(internalPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, internalPostProcessors);beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
复制代码


后面又重新注册 internalPostProcessors 里面的 BeanPostProcessor ,这个是什么操作呢,我们看看具体的注册方法


public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {  // 先移除    this.beanPostProcessors.remove(beanPostProcessor);    if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {      this.hasInstantiationAwareBeanPostProcessors = true;   }   if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {      this.hasDestructionAwareBeanPostProcessors = true;   }  // 再增加    this.beanPostProcessors.add(beanPostProcessor);
复制代码


这么操作一波之后、原来注册的 BeanPostProcessor 的位置就会被移动到 List 的尾部了


我们再回到我们上面的问题,我们的 Student 类明明实现了 BeanPostProcessor 接口,但是却没有被回调到




我们看看对应的代码


List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());for (String ppName : nonOrderedPostProcessorNames) {   BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);   nonOrderedPostProcessors.add(pp);   if (pp instanceof MergedBeanDefinitionPostProcessor) {      internalPostProcessors.add(pp);   }}registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
复制代码


ClassPathXmlApplicationContext构造函数-->refresh()-->registerBeanPostProcessors()
复制代码


当我们在 refresh 的时候、执行到 registerBeanPostProcessors , 我们发现整个 Spring 管理的 BeanDefinition 集合中、只有 Student 是实现了 BeanPostProcessor 接口的、然后我们通过 getBean 方法去获取这个 bean , 注意这个时候 AbstractBeanFactory 中的 beanPostProcessors 除了 Spring 自己加入的一些 BeanPostProcessor 之外,Student 的对象不存在于此( Student 的对象还没被 Spring 创建出来) , 然后就走 getBean 的流程,走到 doCreateBean、走到 initializeBean 然后回调 BeanPostProcessor ,但是这个时候 Student 对象还是不在 beanPostProcessors 集合中、所以就不会打印了。其实可以得出一个结论,实现了 BeanPostProcessor 的 bean 当自身被 Spring 创建的时候、它是不会被回调到的


而上面还留了一个问题


List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>();
复制代码


为啥 orderedPostProcessorNames 和 nonOrderedPostProcessorNames 的集合存放的是一个 String , 而不是直接是 BeanPostProcessor ?主要是为了在创建实现 Ordered 接口的类的时候、即实现了 PriorityOrdered 接口又实现了 BeanPostProcessor 接口的对象得到回调,同理当创建非 PriorityOrdered/Ordered 接口的 bean 时,实现了 PriorityOrdered/Ordered 的 BeanPostProcessor 也能得到回调。这也是一种优先级的关系


发布于: 2020 年 06 月 17 日阅读数: 112
用户头像

CoderLi

关注

微信公众号:CoderLi ,专注于 Java 后端开发 2019.07.14 加入

还未添加个人简介

评论

发布
暂无评论
Spring BeanPostProcessor 你不能不知道的事