写点什么

Spring 源码分析 (七) 扩展接口 BeanPostProcessors 源码分析

  • 2022 年 9 月 04 日
    江西
  • 本文字数:6610 字

    阅读完需:约 22 分钟

Spring源码分析(七)扩展接口BeanPostProcessors源码分析

作者石臻臻,CSDN 博客之星 Top5Kafka Contributornacos Contributor华为云 MVP,腾讯云 TVP,滴滴 Kafka 技术专家 KnowStreaming, 《Kafka 运维与实战宝典》电子书作者。领取《Kafka 运维与实战宝典》PDF 请联系石臻臻


KnowStreaming 是滴滴开源的Kafka运维管控平台, 有兴趣一起参与参与开发的同学,但是怕自己能力不够的同学,可以联系我,当你导师带你参与开源!

BeanPostProcessors 在 spring 中是一个非常重要的扩展接口,它使得我们可以在创建 bean 实例的前后做一些自己的处理;接下来我们就从源码层面来分析一下它是如何发挥作用的;

一、bean 的生成过程



这里写图片描述

二、BeanPostProcessors 简要说明


我们看下 BeanPostProcessors 的接口

public interface BeanPostProcessor { //在初始化之前调用 Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; //在初始化之后调用 Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
复制代码

如果这个接口的某个实现类被注册到某个容器,那么该容器的每个 Bean 在调用初始化方法之前,都会获得该接口实现类的一个回调。容器调用接口定义的方法时会将该受管 Bean 的实例和名字通过参数传入方法,进过处理后通过方法的返回值返回给容器。也就是回调了 postProcessBeforeInitialization 方法

要使用 BeanPostProcessor 回调,就必须先在容器中注册实现该接口的类,那么如何注册呢?BeanFactory 和 ApplicationContext 容器的注册方式不大一样:若使用 BeanFactory,则必须要显示的调用其 addBeanPostProcessor()方法进行注册,参数为 BeanPostProcessor 实现类的实例;如果是使用 ApplicationContext,那么容器会在配置文件在中自动寻找实现了 BeanPostProcessor 接口的 Bean,然后自动注册,我们要做的只是配置一个 BeanPostProcessor 实现类的 Bean 就可以了。

假如我们使用了多个的 BeanPostProcessor 的实现类,那么如何确定处理顺序呢?其实只要实现 Ordered 接口,设置 order 属性就可以很轻松的确定不同实现类的处理顺序了;接口中的两个方法都要将传入的 bean 返回,而不能返回 null,如果返回的是 null 那么我们通过 getBean 方法将得不到目标

根据上面的描述我们可以详细说下其中的两个问题

Partcounter(counterh1)三、ApplicationContext 容器是怎样注册 BeanPostProcessor 的?


AbstractApplicationContext 中的 refresh 方法中有一个 registerBeanPostProcessors 方法

@Override public void refresh() throws BeansException, IllegalStateException { //省略....  // Register bean processors that intercept bean creation.  registerBeanPostProcessors(beanFactory); //省略....  /**  * 1.实例化剩余的所有非延迟加载单例对象  * 2.为什么说是剩余的?因为在上面的registerBeanPostProcessors中已经把所有BeanPostProcessors所有对象都已经实例化过了;  * 3.这加载的时候会判断bean是不是 FactoryBean类型的  *   3.1如果是FactoryBean类型,则getBean(&beanName),这里是把FactoryBean本身的对象给实例化了,而没有调它的getObject方法;  *      3.1.1 还要判断是不是SmartFactoryBean类型的,SmartFactoryBean继承了FactoryBean接口;但是它多了一个 boolean isEagerInit();方法;这个方法就是判断是否需要通过FactoryBean的getObject()生成实例;  *   3.2如果不是FactoryBean类型,直接getBean就行了;  * 其实我们在上一篇分享 FactoryBean的时候,有调用BeanPostProcessors的后置方法,但是很不理解这里为啥还要执行一次,因为讲道理在之前就应该执行过,TODO...看文章....  * 4.还要判断是不是SmartInitializingSingleton接口,这个接口有个afterSingletonsInstantiated方法;  * 循环所以bean判断是不是这个类型的,只要是这个类型就调用afterSingletonsInstantiated方法;  */  finishBeanFactoryInitialization(beanFactory);    //省略..  }

复制代码

counter(counterh2)代码入口

public static void registerBeanPostProcessors(   ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {  /**  *1.代码走到了这里的时候其实 BeanDefinition数据已经被加载了,只是bean还没有被实例化  所以这个是去容器里面找到所有类型为BeanPostProcessor的beanName  */  String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
  //记录所有的beanProcessor数量,在这之前也可能注册了一部分Spring内部的BeanPostProcessors接口,例如:ApplicationContextAwareProcessor  int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;  //貌似只是记录日志用的  beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
  // 优先级最高的BeanPostProcessors,这类最先调用;需要实现PriorityOrdered接口  List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();  //内部BeanPostProcessors  List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();  //继承了Ordered接口,优先级币上面低一点  List<String> orderedPostProcessorNames = new ArrayList<String>();  //这就是普通的了,优先级最低  List<String> nonOrderedPostProcessorNames = new ArrayList<String>();  //下面的这些代码就是遍历所有postProcessorNames,按优先级排序;类型PriorityOrdered>Ordered>普通;在这个类型基础上,还要对他们的order属性就行排序;  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)) {    orderedPostProcessorNames.add(ppName);   }   else {    nonOrderedPostProcessorNames.add(ppName);   }  }
  // First, register the BeanPostProcessors that implement PriorityOrdered.  sortPostProcessors(beanFactory, priorityOrderedPostProcessors);  registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
  // Next, register the BeanPostProcessors that implement Ordered.  List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();  for (String ppName : orderedPostProcessorNames) {   BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);   orderedPostProcessors.add(pp);   if (pp instanceof MergedBeanDefinitionPostProcessor) {    internalPostProcessors.add(pp);   }  }  sortPostProcessors(beanFactory, orderedPostProcessors);  registerBeanPostProcessors(beanFactory, orderedPostProcessors);
  // Now, register all regular BeanPostProcessors.  List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();  for (String ppName : nonOrderedPostProcessorNames) {  //这里要注意一下了,看到没有,这个时候已经调用了getBean来生成实例对象了;   BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);   nonOrderedPostProcessors.add(pp);   if (pp instanceof MergedBeanDefinitionPostProcessor) {    internalPostProcessors.add(pp);   }  }  registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
  // 排序  sortPostProcessors(beanFactory, internalPostProcessors);  //注册  registerBeanPostProcessors(beanFactory, internalPostProcessors);
  // 加入ApplicationListenerDetector  beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext)); }
 /**  * 注册 BeanPostProcessor beans.  * 容器中beanPostProcessors是一个ArrayList来持有这些BeanPostProcessors  */ private static void registerBeanPostProcessors(   ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
  for (BeanPostProcessor postProcessor : postProcessors) {   beanFactory.addBeanPostProcessor(postProcessor);  } }@Override public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {  Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");  this.beanPostProcessors.remove(beanPostProcessor);  this.beanPostProcessors.add(beanPostProcessor);  //将是否 hasInstantiationAwareBeanPostProcessors设置为true   //关于InstantiationAwareBeanPostProcessor作用请看  //https://blog.csdn.net/u010634066/article/details/80321854  if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {   this.hasInstantiationAwareBeanPostProcessors = true;  }  if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {   this.hasDestructionAwareBeanPostProcessors = true;  } }

复制代码

counter(counterh2)answer

ok,代码分析完了,那么这个答案也就很明显了。我们组织一下语言总结一下:

  1. Spring 加载完了所有的 BeanDefinition 之后,找到所有类型为 BeanPostProcessors 的 BeanDefinition 对象;

  2. 根据得到的类型是否实现了 PriorityOrdered>Ordered>无继承 Ordered;在这个优先级基础上,每个实现了 Ordered 接口的(PriorityOrdered 也实现了 Ordered)都有一个 order 属性,还要根据 order 来进行排序;例如有三个类

class PriorityOrderTest implements,BeanPostProcessor, PriorityOrdered 
class OrderTest implements,BeanPostProcessor, Ordered 
class NoneTest implements,BeanPostProcessor 
复制代码

然后 PriorityOrderTest 有两个实例 P1;p1.getOrder()=1P2;p2.getOrder()=2OrderTest 也有两个实例 O1;o1.getOrder()=3O2;o2.getOrder()=4None 一个实例 n1:n1.getOrder()=100;那么最终调用的顺序是 p2>p1>o2>o1>n1

3.把 BeanPostProcessors 注册到 beanFactory 的时候,注册是是 BeanPostProcessors 实例!,因为提前调用了 getBean()方法得到了 BeanPostProcessors 实例;


Partcounter(counterh1)三、什么时候调用 BeanPostProcessors 的方法呢?


调用的地方比较多,还有很多 Spring 内部的接口,还有其他的比如 MergedBeanDefinitionPostProcessor 等也继承了 BeanPostProcessors 接口的扩展接口,我们这里先只分析我们自己继承这个 BeanPostProcessors 接口的实例是什么时候被调用的;##代码入口第一个调用的地方

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)   throws BeanCreationException {   //省略...   populateBean(beanName, mbd, instanceWrapper);   if (exposedObject != null) {   //BeanPostProcessors两个方法都在这里面    exposedObject = initializeBean(beanName, exposedObject, mbd);   }   //省略....}
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { //省略....if (mbd == null || !mbd.isSynthetic()) { //初始化之前   wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);  }
  try {//初始化   invokeInitMethods(beanName, wrappedBean, mbd);  }  //初始化之后if (mbd == null || !mbd.isSynthetic()) {   wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);  } //省略...
//注意 每一个实例对象触发这个的时候 都是执行所有的BeanPostProcessors实例对象@Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)   throws BeansException {
  Object result = existingBean;  for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {  //这里是循环  // result =BeanPostProcessor调用执行方法;返回的对象还是result,只是有可能被某个BeanPostProcessor加强了 beanProcessor.postProcessAfterInitialization(result, beanName);   if (result == null) {    return result;   }  }  return result; }
复制代码

通过这个代码可以清晰的知道调用时间;那我们重新理一下注册和使用

  1. Spring 识别 BeanPostProcessors,通过提前 getBean 拿到实例,getBean 也会触发接口的两个方法,但是这个时候当前 BeanPostProcessors 实例还没有被注册进去;

  2. 注册获取到的 BeanPostProcessors 实例;

  3. 后面只要有对象调用 getBean 就会触发 BeanPostProcessors 的方法;不管是 BeanPostProcessors.getBean();还是 finishBeanFactoryInitialization()注册剩余的实例都会触发;

counter(counterh2)第二个调用的地方 FactoryBeanRegistrySupport


上面文章

protected Object getObjectForBeanInstance(){ //省略.. /** *能执行这个方法是因为 当bean时FactoryBean的时候并且 beanName没有前缀 & ;则调用下面的方法 */  object = getObjectFromFactoryBean(factory, beanName, !synthetic); //省略...}
复制代码

FactoryBeanRegistrySupport.getObjectFromFactoryBean

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { //省略... /** * 最终调用了applyBeanPostProcessorsAfterInitialization方法; */ object = postProcessObjectFromFactoryBean(object, beanName); //省略... }
复制代码

想一想为什么要在这里执行一下 postProcessAfterInitialization 方法呢?在第一种情况的时候,我们知道只要 getBean()操作都会触发两个接口的两个方法;并且容器会帮我们把非延迟加载的单例对象都给初始化;但是如果我们的对象是 FactoryBean 对象呢?容器主动帮我们加载的是 FactoryBean 本身的对象,而不是通过 FactoryBean 的 getObject 的对象;我们在 getObject 方法也是实例化的一个过程,所以也要调用 postProcessAfterInitialization 方法;

Partcounter(counterh1)四、总结

1.BeanPostProcessors 注册发生在容器启动的时候;自动注册 BeanPostProcessors 类型;

2.只要调用 getBean 初始化对象都会触发 BeanPostProcessors 接口的两个方法,并且是所有 BeanPostProcessors 实例都会触发;

3.如果是 FactoryBean 类型,容器不会帮我们自动初始化它产生的实例除非是 SmartFactoryBean 实例,并且它的 isEagerInit()返回的是 true;IOC 容器才会也帮我们调用它的 getObject 方法来生成实例;

Partcounter(counterh1)五、后续


分析这篇源码的时候遇到了其他的一些需要单独分析的问题,先占个坑

counter(counterh2)1.SmartFactoryBean 的使用

counter(counterh2)2.Spring InstantiationAwareBeanPostProcessor 接口的分析

Spring扩展接口InstantiationAwareBeanPostProcessor解析


发布于: 刚刚阅读数: 5
用户头像

关注公众号: 石臻臻的杂货铺 获取最新文章 2019.09.06 加入

进高质量滴滴技术交流群,只交流技术不闲聊 加 szzdzhp001 进群 20w字《Kafka运维与实战宝典》PDF下载请关注公众号:石臻臻的杂货铺

评论

发布
暂无评论
Spring源码分析(七)扩展接口BeanPostProcessors源码分析_spring_石臻臻的杂货铺_InfoQ写作社区