栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Framework 源码阅读(五):BeanFactoryPostProcessor

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Framework 源码阅读(五):BeanFactoryPostProcessor

Spring framework 源码阅读(五):BeanFactoryPostProcessor

在上一篇博客中介绍了BeanPostProcessor和Bean的生命周期,BeanPostProcessor是允许自定义修改新bean实例的工厂钩子,在新bean实例初始化前后调用BeanPostProcessor中的方法,而通过FactoryBean创建的新bean实例和Spring通过反射创建的新bean实例在应用BeanPostProcessor方面有所不同,前者只会调用BeanPostProcessor中的postProcessAfterInitialization方法,而后者会调用BeanPostProcessor中的所有方法,想详细了解这些内容可以阅读这篇博客:

  • Spring framework 源码阅读(四):BeanPostProcessor和Bean的生命周期

那BeanFactoryPostProcessor有啥用?看命名跟BeanPostProcessor差不多,其实功能也差不多,都是自定义修改实例,只是修改的主体不同,BeanPostProcessor修改的主体是bean,而BeanFactoryPostProcessor修改的主体是bean定义,不了解bean定义,可以阅读这篇博客:

  • Spring framework 源码阅读(二):BeanDefinition的作用

注意,BeanFactoryPostProcessor和BeanPostProcessor都是自定义修改实例(实例主体不同),在两者应用时,实例肯定是已经实例化了(通过反射调用或者FactoryBean直接调用这两种方式,调用了实例类的构造函数)。

BeanFactoryPostProcessor接口源码如下(@FunctionalInterface表示该接口是函数式接口,可以使用lambda表达式直接赋值):

@FunctionalInterface
public interface BeanFactoryPostProcessor {

	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
  • 工厂钩子:允许自定义修改应用程序上下文(application context)的 bean 定义,调整上下文底层 bean 工厂的 bean 属性值。对于自定义配置文件很有用,这些文件覆盖了应用程序上下文中配置的 bean 属性。 有关满足此类配置需求的开箱即用解决方案,请参阅PropertyResourceConfigurer及其具体实现。BeanFactoryPostProcessor可以与bean定义交互并修改bean定义,但绝不能与bean实例交互(这样做可能会导致 bean过早实例化、违反容器意愿并导致意外的副作用)。 如果需要与bean实例交互,请考虑实现BeanPostProcessor 。
  • 注册:ApplicationContext在其bean定义中自动检测BeanFactoryPostProcessor bean,并在创建任何其他bean之前应用它们。 BeanFactoryPostProcessor也可以通过ConfigurableApplicationContext以编程方式注册。
  • 顺序:在ApplicationContext中自动检测的BeanFactoryPostProcessor bean将根据PriorityOrdered和Ordered语义进行排序。 相比之下,使用ConfigurableApplicationContext以编程方式注册的BeanFactoryPostProcessor bean将按注册顺序应用; 对于以编程方式注册的PostProcessor,通过实现PriorityOrdered或Ordered接口表达的任何排序语义都将被忽略。 此外,@Order注解不会被BeanFactoryPostProcessor bean考虑在内。

博主早期的博客,可能排版不好看以及语言不严谨,也推荐阅读一下,可以对函数式接口(@FunctionalInterface)有一个直观的认识。

  • JDK8 新特性Function接口
创建module

先在Spring framework源码中增加一个application module,这在之前的博文中已经介绍过了,这里就不再赘述:

  • 编译 Spring framework 5.2.17源码 & 在源码中使用 ApplicationContext 获取定义的Bean


TaskBeanDefinitionProcess类(实现BeanFactoryPostProcessor接口):

package com.kaven.process;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

import java.util.Objects;



@Component
public class TaskBeanDefinitionProcess implements BeanFactoryPostProcessor {

    // 将自定义的作用域字符串myScope转换成singleton
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		BeanDefinition bd = beanFactory.getBeanDefinition("myTask");
		if(Objects.equals(bd.getScope(), "myScope")) {
			bd.setScope("singleton");
		}
	}
}

启动类Application:

package com.kaven;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.*;

import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;



@ComponentScan({"com.kaven"})
public class Application {

	public static void main(String[] args) {
	    // 创建应用上下文
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 在应用上下文中添加BeanFactoryPostProcessor
        // 将myTask bean的BeanDefinition的懒加载设置为false
		applicationContext.addBeanFactoryPostProcessor((beanFactory) -> {
			beanFactory.getBeanDefinition("myTask").setLazyInit(false);
		});
        
        // 注册组件类
		applicationContext.register(Application.class);

        // refresh
		applicationContext.refresh();

        // 获取myTask bean
		Task task = (Task) applicationContext.getBean("myTask");
		System.out.println("taskCount: " + task.addTask());
		
        // 获取myTask bean的BeanDefinition
		BeanDefinition taskBeanDefinition = applicationContext.getBeanDefinition("myTask");
		System.out.println(taskBeanDefinition.getScope());
		System.out.println(taskBeanDefinition.isLazyInit());

        // 获取应用上下文中的BeanDefinition数量和名称
		System.out.println("BeanDefinitionCount: " + applicationContext.getBeanDefinitionCount());
		Arrays.stream(applicationContext.getBeanDefinitionNames()).forEach(System.out::println);
	}

    // myTask bean
	@Bean(value = "myTask")
	@Scope("myScope")
	@Lazy
	public Task getTask() {
		return new Task();
	}

	public static class Task{
		private final AtomicInteger taskCount;

		public Task() {
			taskCount = new AtomicInteger(0);
		}

		public int addTask() {
			return taskCount.incrementAndGet();
		}
	}
}

输出结果:

taskCount: 1
singleton
false
BeanDefinitionCount: 7
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
application
taskBeanDefinitionProcess
myTask

很显然符合预期,myTask bean的作用域从自定义作用域字符串myScope转换成了singleton,懒加载也设置成了false,这些都是因为TaskBeanDefinitionProcess类的postProcessBeanFactory方法以及下方的lambda表达式起作用了。

(beanFactory) -> {
	 beanFactory.getBeanDefinition("myTask").setLazyInit(false);
}
源码分析

开始Debug。


执行这行代码:

applicationContext.refresh();

调用了AbstractApplicationContext抽象类的refresh方法(删除了部分代码):

	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 准备此上下文以进行刷新
			prepareRefresh();

			// 告诉子类刷新内部bean工厂
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 准备在此上下文中使用的bean工厂
			prepareBeanFactory(beanFactory);

			try {
				// 允许在上下文子类中对bean工厂进行postProcess
				postProcessBeanFactory(beanFactory);

				// 调用在上下文中注册的BeanFactoryPostProcessor
				invokeBeanFactoryPostProcessors(beanFactory);

				// 注册BeanPostProcessor
				registerBeanPostProcessors(beanFactory);

				// 初始化此上下文的消息源
				initMessageSource();

				// 为此上下文初始化事件多播器
				initApplicationEventMulticaster();

				// 初始化特定上下文子类中的其他特殊bean
				onRefresh();

				// 检查监听器bean并注册它们
				registerListeners();

				// 实例化所有剩余的(非延迟加载)单例
				finishBeanFactoryInitialization(beanFactory);

				// 发布相应的事件
				finishRefresh();
			}
		}
	}

之后会调用PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors方法(删除了部分代码,看注释即可):

	public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) {

		// 如果有的话,首先调用BeanDefinitionRegistryPostProcessor
		Set processedBeans = new HashSet<>();

		if (beanFactory instanceof BeanDefinitionRegistry) {
			
			// 调用BeanDefinitionRegistryPostProcessor
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

			// 调用到目前为止处理的所有处理器的postProcessBeanFactory回调
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}
		else {
			// 调用在上下文实例中注册的BeanFactoryPostProcessor
			// 但beanFactory不能instanceof BeanDefinitionRegistry
			// 如果beanFactory instanceof BeanDefinitionRegistry
			// 执行上面的invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory)
			// 也会调用在上下文实例中注册的BeanFactoryPostProcessor
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		// 获取BeanFactoryPostProcessor bean的名称
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		// 调用BeanFactoryPostProcessor
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

		// 清除缓存的合并bean定义
		// 因为BeanFactoryPostProcessor可能已经修改了原始元数据,例如替换值中的占位符
		beanFactory.clearmetadataCache();
	}

BeanDefinitionRegistryPostProcessor接口源码:

// 对标准BeanFactoryPostProcessor SPI的扩展
// 允许在常规BeanFactoryPostProcessor检测开始之前注册bean定义
// 特别是, BeanDefinitionRegistryPostProcessor可以注册BeanFactoryPostProcessor bean定义。
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

    // 在标准初始化之后修改应用程序上下文的内部bean定义注册表
    // 所有常规bean定义都将被加载,但尚未实例化任何bean
    // 这允许在下一个后处理阶段开始之前添加更多的bean定义
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}

所以,BeanFactoryPostProcessor应用时,bean定义已经注册好了,和前面描述的一致。

但我们并没有提供BeanDefinitionRegistryPostProcessor接口的实现,为什么还能注册bean定义?还记得代码的输出结果中有几个Spring内置的bean定义:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory

org.springframework.context.annotation.internalConfigurationAnnotationProcessor对应的bean类是ConfigurationClassPostProcessor类。

这在BeanDefinition的作用这篇博客中有介绍。

	    
	    public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
			  "org.springframework.context.annotation.internalConfigurationAnnotationProcessor";

		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

ConfigurationClassPostProcessor类(实现了BeanDefinitionRegistryPostProcessor接口):

// 这个PostProcessor是优先级排序的,因为在任何其他BeanFactoryPostProcessor执行之前
// 在@Configuration类中声明的任何@Bean方法都必须注册其相应的bean定义,这一点很重要
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
		...
}

当然我们这里没有使用@Configuration注解,但很显然@ComponentScan({"com.kaven"})的效果也是类似的。

再回到PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors方法,通过Debug,可以知道在调用invokeBeanFactoryPostProcessors方法前,如下图所示的5个bean定义就已经注册了,这在BeanDefinition的作用这篇博客中有介绍,这里不再赘述。所以,还剩下myTask和taskBeanDefinitionProcess这两个bean的bean定义没有注册。

调用了ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry方法后,myTask和taskBeanDefinitionProcess这两个bean的bean定义也会被注册。

而myTask bean的bean定义还没有被修改,因为自定义的两个BeanFactoryPostProcessor还没有应用。

在这里会应用使用lambda表达式定义的BeanFactoryPostProcessor(beanFactory instanceof BeanDefinitionRegistry为true,不然下面else部分那一行代码也会执行该BeanFactoryPostProcessor)。

懒加载设置成了false,而作用域还是自定义的作用域字符串myScope。

在这里会应用我们实现的BeanFactoryPostProcessor(TaskBeanDefinitionProcess类)。



到这里作用域也修改成功了。

BeanFactoryPostProcessor能被应用,说明这些BeanFactoryPostProcessor bean已经创建好了(能修改其他bean的bean定义,当然需要提取创建好,以便应用,当然使用lambda表达式定义的BeanFactoryPostProcessor不需要被创建,类似使用匿名内部类,本身就是一个实例,只是原理有些不同):

invokeBeanFactoryPostProcessors方法开始执行时,还没有已经创建的对象。

执行完下面这部分代码,ConfigurationClassPostProcessor类对应的bean就被创建好了(通过beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)创建),该bean也会注册之前说过的那两个bean定义。

			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();


执行完下面这部分代码,BeanFactoryPostProcessor bean(TaskBeanDefinitionProcess实例)也创建好了(通过beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)创建)。

List nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}


通过上面的分析,可以知道BeanFactoryPostProcessor可以用于注册bean定义以及修改bean定义等,修改bean定义时,这些bean定义已经注册到了bean工厂中。

阅读源码需要耐心,一步步进行Debug,每个人的理解不同,如果博主有说错的地方或者大家有不同的见解,欢迎大家评论补充。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/425505.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号