Spring源码学习:BeanPostProcessor注册和执行时机

目录

  • 前言
  • 1 BeanPostProcessors作用
  • 2 源码分析
    • 2.1 BeanPostProcessors注册时机
      • 2.1.1 注册beanPostProcessorChecker
      • 2.1.2 各种优先级BeanPostProcessor进行排序注册
      • 2.1.3 重新注册ApplicationListenerDetector
    • 2.2 BeanPostProcessors执行时机
  • 3 扩展示例
  • 总结

前言

后置处理器是Spring框架提供的对外扩展点,通过实现对应接口,可以对bean进行各种操作(bean定义bd进行修改或者对初始化前后的bean进行各种修改),其中之一是BeanPostProcessor,本文主要从源码角度了解BeanPostProcessor的原理和执行过程。

1 BeanPostProcessors作用

BeanPostProcessor作为Spring框架重要的扩展点,对外提供了对bean实例化后,操作的空间,主要是涉及到对bean执行初始化方法前后调用对应方法实现对bean的各种功能增强,比如spring aop是利用BeanPostProcessor实现的代理增强。

2 源码分析

BeanPostProcessor的主要分析应该包括两部分:

  1. 注册bd定义,实例化和注册对应的bean实例
  2. 判断执行各种BeanPostProcessor的执行时机

2.1 BeanPostProcessors注册时机

以AnnotationConfigApplicationContext为例,对BeanPostProcessor的注册在AbstractApplicationContext.refresh方法
Spring源码学习:BeanPostProcessor注册和执行时机_第1张图片该方法最终调用的是下面方法进行的核心处理
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this)
主要逻辑完成三件事

  1. 注册eanPostProcessorChecker记录特定情况日志
  2. 对各种优先级BeanPostProcessor进行排序,注册
  3. 重新注册ApplicationListenerDetector,移动到处理器尾部

2.1.1 注册beanPostProcessorChecker

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

		// Register BeanPostProcessorChecker that logs an info message when
		// a bean is created during BeanPostProcessor instantiation, i.e. when
		// a bean is not eligible for getting processed by all BeanPostProcessors.
		/**
		 * 目标总数:获取已经实例化的BeanPostProcessor+ 1(BeanPostProcessorChecker) + 已经注册的bd但是还未实例化
		 * BeanPostProcessorChecker作用:
		 * 	在所有BeanPostProcessor实例化期间,如果有bean创建,则打印日志记录-该bean的初始化可能不能得到所有后置处理器的处理,
		 * 	以为还有已经注册bd,但是未实例化的bd
		 */
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

通过BeanPostProcessorChecker判断BeanPostProcessor注册期间是否有注册新的bean,检测逻辑如下图
Spring源码学习:BeanPostProcessor注册和执行时机_第2张图片
通过this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount,判断是否已经完成所有BeanPostProcessor的注册

2.1.2 各种优先级BeanPostProcessor进行排序注册

该过程就是根据BeanPostProcessor实现的各种接口判断优先级,逻辑比较简单:

/**
		 * 将后置处理器按照以下四类进行排序添加
		 * 1. 实现PriorityOrdered接口
		 * 2. 实现Ordered接口
		 * 3. 实现MergedBeanDefinitionPostProcessor,内部后置处理器
		 * 4. 其它后置处理器
		 * 对上述的处理分别按照类别进行排序,然后添加到beanPostProcessors缓存中
		 */
		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)) {
				//getBean--实例化,初始化bd
				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(priorityOrderedPostProcessors, beanFactory);
		//实例化注册
		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

		// Next, register the BeanPostProcessors that implement Ordered.
		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);

		// Finally, re-register all internal BeanPostProcessors.
		sortPostProcessors(internalPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, internalPostProcessors);

将后置处理器按照以下四类进行排序添加
1. 实现PriorityOrdered接口
2. 实现Ordered接口
3. 实现MergedBeanDefinitionPostProcessor,内部后置处理器
4. 其它后置处理器

	 对上述的处理分别按照类别进行排序,然后添加到beanPostProcessors缓存中

注册逻辑如下,主要是根据bean工厂类型,有一个批量添加(底层CopyOnWriteArrayList复制加锁批量添加)的区别
Spring源码学习:BeanPostProcessor注册和执行时机_第3张图片

2.1.3 重新注册ApplicationListenerDetector

由于在prepareBeanFactory时已经添加了ApplicationListenerDetector,这里之所以要重新添加是为了能够处理代理bean,主要代码就一句如下图
Spring源码学习:BeanPostProcessor注册和执行时机_第4张图片
官方注释意思应该是拾取代理,从而放最后一个进行注册,对代理bean也能够进行处理,避免先执行而无法获取代理bean。

2.2 BeanPostProcessors执行时机

在创建bean,执行bean初始化前后执行具体是doCreateBean–>initializeBean这个方法

Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			// 处理初始化前执行postProcessBeforeInitialization
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			//初始化
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			//处理初始化后执行postProcessAfterInitialization
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

在执行初始化bean前后调用,调用函数如下就是根据添加顺序依次处理,这也是为什么需要把ApplicationListenerDetector放到末尾处理,以防止较早处理获取不到代理对象。

3 扩展示例

首先自定义一个实现BeanPostProcessor的类和待处理的类

  1. 待处理的类
    Spring源码学习:BeanPostProcessor注册和执行时机_第5张图片
  2. MyPostProcessor
    Spring源码学习:BeanPostProcessor注册和执行时机_第6张图片

输出结果
Spring源码学习:BeanPostProcessor注册和执行时机_第7张图片
可以看出初始化前后拦截D做的操作

总结

本篇文章主要是对BeanPostProcessor作用、注册和执行时机源码进行了学习,并对如何使用BeanPostProcessor扩展做了一个测试。

你可能感兴趣的:(springboot,java,后端)