前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >BeanPostProcessor 是在何时介入 Bean 创建的?

BeanPostProcessor 是在何时介入 Bean 创建的?

作者头像
江南一点雨
发布2023-10-26 08:21:03
1500
发布2023-10-26 08:21:03
举报
文章被收录于专栏:玩转JavaEE玩转JavaEE

今天来和各位小伙伴详细分析一下 BeanPostProcessor。今天这篇是原理分析,基本用法松哥之前已经讲过了,有视频也有文章,对视频感兴趣的小伙伴戳这里:Spring源码应该怎么学?

不同于前面和大家分享的 BeanFactoryPostProcessor,BeanPostProcessor 从名字上就能看出来,这是一个 Bean 的后置处理器,也就是说,BeanPostProcessor 其实主要是对已经创建出来的 Bean 做一些后置处理,而 BeanFactoryPostProcessor 主要是针对 BeanDefinition 做后置处理(此时 Bean 对象还没创建出来)。

但是,BeanPostProcessor 家族里边也有例外,即 MergedBeanDefinitionPostProcessor,这是一个 BeanPostProcessor,但是却可以处理 BeanDefinition。

这一切都是咋回事呢?我们今天就来分析分析。

1. BeanPostProcessor

首先我们先来看一下 BeanPostProcessor 接口的定义:

代码语言:javascript
复制
public interface BeanPostProcessor {

 @Nullable
 default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  return bean;
 }

 @Nullable
 default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  return bean;
 }

}

这里就是两个方法,理解这两个方法有一个大的前提,就是此时 Spring 容器已经通过 Java 反射创建出来 Bean 对象了,只不过在初始化这个 Bean 对象的时候,又提供了一些配置接口:

  • postProcessBeforeInitialization:这个是在 Bean 初始化之前触发,此时我们已经有一个 Bean 对象了,但是 Bean 中一些生命周期方法如 InitializingBean 接口的 afterPropertiesSet 方法、自定义的 init-method 方法等都尚未执行,在这些方法执行之前触发 postProcessBeforeInitialization 方法。
  • postProcessAfterInitialization:类似于上面,在 afterPropertiesSet 和自定义的 init-method 之后触发该方法。

BeanPostProcessor 的应用非常广泛,在整个 Spring 体系中,也扮演了非常重要的角色,如 @Bean 注解的解析、AOP 动态代理的生成等等许多我们日常使用的功能,都是通过 BeanPostProcessor 来实现的。

2. MergedBeanDefinitionPostProcessor

MergedBeanDefinitionPostProcessor 算是整个 BeanPostProcessor 家族中比较另类的一个接口了,它虽然是 BeanPostProcessor,但是却可以处理 BeanDefinition。MergedBeanDefinitionPostProcessor 介入的时机就是 Bean 创建成功之后,Bean 中各个属性填充之前。

MergedBeanDefinitionPostProcessor 用于在 Bean 定义合并之后对合并后的 Bean 进行后置处理。它的作用是允许开发者在 Bean 定义合并完成后,对合并后的 Bean 进行自定义的修改或扩展操作。通常情况下,这个接口用于处理带有注解的 Bean 定义,例如 @Autowired 或 @Value 等注解的处理。通过实现 MergedBeanDefinitionPostProcessor 接口,开发者可以在 Bean 定义合并后,对这些注解进行解析和处理,以实现自定义的逻辑。

来看下 MergedBeanDefinitionPostProcessor 接口:

代码语言:javascript
复制
public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {

 void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);

 default void resetBeanDefinition(String beanName) {
 }

}

这里就两个方法,一个是处理合并后的 BeanDefinition,还有一个是重置 Bean 的。

3. 收集 BeanPostProcessor

接下来我们来看 BeanPostProcessor 的处理流程,首先第一步就是在容器启动的时候,收集到用户注册在系统中的 BeanPostProcessor,无论是 Java 配置还是 XML 配置,在 refresh 方法中都会调用到 registerBeanPostProcessors,这个方法就是用来收集 BeanPostProcessor 的。

代码语言:javascript
复制
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
 PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
public static void registerBeanPostProcessors(
  ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
 int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
 beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
 List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
 List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
 List<String> orderedPostProcessorNames = new ArrayList<>();
 List<String> nonOrderedPostProcessorNames = new ArrayList<>();
 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);
  }
 }
 sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
 registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
 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);
 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));
}

这里的代码我就不逐行解释了,我来说一下整体的处理思路。

这里用来存储 BeanPostProcessor 的集合一共有四个,分别是:

  • priorityOrderedPostProcessors:由于 BeanPostProcessor 可能存在多个,所以我们需要给这多个 BeanPostProcessor 进行排序,排序的方式有两种,一种就是在定义 BeanPostProcessor 的时候,让其实现 PriorityOrdered 接口,那么这里就是把所有实现了 PriorityOrdered 接口的 BeanPostProcessor 收集到一起。
  • orderedPostProcessors:类似于上面的,这里是收集所有实现了 Ordered 接口的 BeanPostProcessor。
  • nonOrderedPostProcessors:这个里边保存了所有不需要排序的 BeanPostProcessor。
  • internalPostProcessors:这个里边保存了 MergedBeanDefinitionPostProcessor 类型的 BeanPostProcessor,前三种互相之间不会重复,而 internalPostProcessors 可能会和前三种有重复。

将收集并且排序好的 BeanPostProcessor,调用 registerBeanPostProcessors 方法进行注册:

代码语言:javascript
复制
private static void registerBeanPostProcessors(
  ConfigurableListableBeanFactory beanFactory, List<? extends BeanPostProcessor> postProcessors) {
 if (beanFactory instanceof AbstractBeanFactory abstractBeanFactory) {
  // Bulk addition is more efficient against our CopyOnWriteArrayList there
  abstractBeanFactory.addBeanPostProcessors(postProcessors);
 }
 else {
  for (BeanPostProcessor postProcessor : postProcessors) {
   beanFactory.addBeanPostProcessor(postProcessor);
  }
 }
}

这里最终就是把收集到的 BeanPostProcessor 添加到容器的 beanPostProcessors 变量中。

现在,容器中已经有了 BeanPostProcessor 了,接下来看什么时候执行。

4. 触发 BeanPostProcessor

BeanPostProcessor 的执行分为两种情况,一种是执行 MergedBeanDefinitionPostProcessor 类型的 BeanPostProcessor,还有一种是执行普通的 BeanPostProcessor,我们分别来看。

在创建 Bean 的关键方法 AbstractAutowireCapableBeanFactory#doCreateBean 中,有这样几个关键步骤:

代码语言:javascript
复制
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
  throws BeanCreationException {
    // 初始化 Bean 实例
 BeanWrapper instanceWrapper = null;
 if (mbd.isSingleton()) {
  instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
 }
 if (instanceWrapper == null) {
  instanceWrapper = createBeanInstance(beanName, mbd, args);
 }
 Object bean = instanceWrapper.getWrappedInstance();
 Class<?> beanType = instanceWrapper.getWrappedClass();
 if (beanType != NullBean.class) {
  mbd.resolvedTargetType = beanType;
 }
 // Allow post-processors to modify the merged bean definition.
 synchronized (mbd.postProcessingLock) {
  if (!mbd.postProcessed) {
   try {
    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
   }
   catch (Throwable ex) {
    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
      "Post-processing of merged bean definition failed", ex);
   }
   mbd.markAsPostProcessed();
  }
 }
    //省略
 try {
  populateBean(beanName, mbd, instanceWrapper);
  exposedObject = initializeBean(beanName, exposedObject, mbd);
 }
    //省略
 return exposedObject;
}

大家看到,在初始化 Bean 实例之后,有一个 applyMergedBeanDefinitionPostProcessors 方法,这个方法就是用来触发 MergedBeanDefinitionPostProcessor 执行的。

populateBean 方法是给 Bean 的各个属性填充值的,填充完成之后,调用 initializeBean 方法进行剩余的初始化工作,在 initializeBean 方法中,调用了其余的 BeanPostProcessor。

4.1 触发 MergedBeanDefinitionPostProcessor

代码语言:javascript
复制
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
 for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
  processor.postProcessMergedBeanDefinition(mbd, beanType, beanName);
 }
}

4.2 触发其他 BeanPostProcessor

代码语言:javascript
复制
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
 invokeAwareMethods(beanName, bean);
 Object wrappedBean = bean;
 if (mbd == null || !mbd.isSynthetic()) {
  wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
 }
 try {
  invokeInitMethods(beanName, wrappedBean, mbd);
 }
 catch (Throwable ex) {
  throw new BeanCreationException(
    (mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
 }
 if (mbd == null || !mbd.isSynthetic()) {
  wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
 }
 return wrappedBean;
}

大家看这个顺序,先是调 applyBeanPostProcessorsBeforeInitialization,这个里边最终就触发到了 BeanPostProcessor#postProcessBeforeInitialization 方法;然后调用 invokeInitMethods,afterPropertiesSet 和自定义的 init-method 都在这里被触发;最后调用 applyBeanPostProcessorsAfterInitialization,这个里边最终就触发到 BeanPostProcessor#postProcessAfterInitialization 方法。

好啦,这就是和小伙伴们梳理的 BeanPostProcessor 原理了,感兴趣的小伙伴可以自己 DEBUG 跑一遍哦~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-10-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 江南一点雨 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. BeanPostProcessor
  • 2. MergedBeanDefinitionPostProcessor
  • 3. 收集 BeanPostProcessor
  • 4. 触发 BeanPostProcessor
    • 4.1 触发 MergedBeanDefinitionPostProcessor
      • 4.2 触发其他 BeanPostProcessor
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档