Spring 核心方法 refresh 刷新流程简要概述及相关源码扩展实现(一)

前言

在陈旧系统中都是使用 SSM 架构进行搭建,Spring 源码是后续深入理解学习 SpringBoot、SpringCloud 组件所必须依赖的,只是不再采用 XML 方式来进行配置使用,在这里,主要是回顾下最初在使用 Spring 时的核心类「ClassPathXmlApplicationContext」实例过程以及配置文件加载的详细过程,因为后续的核心方法 refresh 内容讲解也得从此处开始讲起.
文章内容有点长,可以分目录节点进行阅读,比较想深入理解的方法可以点击文章目录入口.

Spring 启动流程解析

在这里插入图片描述
新建 ApplicationContext 上下文对象整体流程如下

  1. PathMatchingResourcePatternResolver:创建一个资源模式解析器(其实就是用来解析 xml 配置文件),内部创建了 Ant 方式表达式语言匹配器
// 创建 Ant【表达式语言】 方式的路径匹配器
private PathMatcher pathMatcher = new AntPathMatcher();
  1. setConfigLocations:设置应用程序上下文的配置路径

  2. customizePropertySources:在创建标准化环境对象(StandardEnvironment)时 createEnvironment() 会执行父类【AbstractEnvironment】构造方法加载这两项值【systemProperties:系统属性值,systemEnvironment:系统环境值】

protected void customizePropertySources(MutablePropertySources propertySources) {
		propertySources.addLast(new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME,getSystemProperties()));
		propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,getSystemEnvironment()));
}
  1. resolveRequiredPlaceholders:解析占位符信息

    创建 PropertyPlaceholderHelper 处理类

    doResolvePlaceholders 执行解析操作

    在其内部递归调用 PropertyPlaceholderHelper#parseStringValue 方法从系统属性和系统环境中解析占用符拿到具体值,递归的原因是因为可能出现这种情况【spring-${username${nickname}}.xml】

Refresh 内部方法全解析

prepareRefresh

容器刷新前的准备工作

protected void prepareRefresh() {
		// 设置容器启动的时间
		this.startupDate = System.currentTimeMillis();
		// 容器的关闭标志位
		this.closed.set(false);
		// 容器的激活标志位
		this.active.set(true);
		// 记录日志
		if (logger.isDebugEnabled()) {
			if (logger.isTraceEnabled()) {
				logger.trace("Refreshing " + this);
			}
			else {
				logger.debug("Refreshing " + getDisplayName());
			}
		}
		// Initialize any placeholder property sources in the context environment.
		// 留给子类覆盖扩展,初始化属性资源,钩子函数
		initPropertySources();

		// Validate that all properties marked as required are resolvable:
		// see ConfigurablePropertyResolver#setRequiredProperties
		// 创建并获取环境对象,验证需要的属性文件是否都已经放入环境中,如果没有放入就抛出异常
		getEnvironment().validateRequiredProperties();

		// Store pre-refresh ApplicationListeners...
		// 判断刷新前的应用程序监听器集合是否为空,如果为空,则将监听器添加到此集合中
		if (this.earlyApplicationListeners == null) {
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
			// Reset local application listeners to pre-refresh state.
			// 如果不等于空,则清空集合元素对象
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}

		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		// 创建刷新前的监听事件集合
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

设置容器的启动时间、设置活跃状态为 true、设置关闭状态为 false、获取 Environment 对象,并加载当前的系统属性值到 Environment 对象中、验证必需的属性是否在环境中存在,如果没有则抛出异常、准备监听器和监听事件的集合对象,默认为空的集合.
该方法流程里面有一个扩展点「初始化属性源交由子类去扩展,可以在其下自定义一些属性,要求其拥有其必须依赖的属性才能正常的运行」

public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {

    public MyClassPathXmlApplicationContext(String... configLocations){
        super(configLocations);
    }

    @Override
    protected void initPropertySources() {
        System.out.println("扩展initPropertySource");
        // 若系统属性中不存在 username,会抛出异常.
        getEnvironment().setRequiredProperties("username");
    }
}

obtainFreshBeanFactory

创建容器对象【DefaultListableBeanFactory】加载 xml 配置文件的属性值到当前工厂中,最重要的就是 BeanDefinition

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	// 初始化 BeanFactory,并进行 XML 文件读取,并将得到的 BeanFactory 记录在当前实体的属性中
	refreshBeanFactory();
	// 返回当前实体 beanFactory 属性
	return getBeanFactory();
}
AbstractApplicationContext 类以及实现子类

AbstractApplicationContext 子类 AbstractRefreshableApplicationContext 继承重写以下方法,XML 启动容器时是该入口来实现
因为 AbstractRefreshableApplicationContext 是 ClassPathXmlApplicationContext 的父类
ClassPathXmlApplicationContext 继承关系

@Override
protected final void refreshBeanFactory() throws BeansException {
	// 如果存在beanFactory,则销毁beanFactory
	if (hasBeanFactory()) {
		destroyBeans();
		closeBeanFactory();
	}
	try {
		// 创建DefaultListableBeanFactory对象
		DefaultListableBeanFactory beanFactory = createBeanFactory();
		// 为了序列化指定id,可以从id反序列化到beanFactory对象
		beanFactory.setSerializationId(getId());
		// 定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖
		customizeBeanFactory(beanFactory);
		// 初始化documentReader,并进行XML文件读取及解析,默认命名空间的解析,自定义标签的解析
		loadBeanDefinitions(beanFactory);
		this.beanFactory = beanFactory;
	}
	catch (IOException ex) {
		throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
	}
}

AbstractApplicationContext 子类 GenericApplicationContext 继承重写以下方法,SpringBoot 是该入口来实现:

protected final void refreshBeanFactory() throws IllegalStateException {
	if (!this.refreshed.compareAndSet(false, true)) {
		throw new IllegalStateException(
				"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
	}
	this.beanFactory.setSerializationId(getId());
}

涉及到 Web 容器启动流程中在 createApplicationContext 方法中会根据类型创建一个上下文对象:AnnotationConfigServletWebServerApplicationContext

protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {
        try {
            switch(this.webApplicationType) {
            case SERVLET:
                contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                break;
            case REACTIVE:
                contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
                break;
            default:
                contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
            }
        } catch (ClassNotFoundException var3) {
            throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
        }
    }

    return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
}

再查看它的类关系图就清楚了
GenericApplicationContext 继承关系

AbstractRefreshableApplicationContext#obtainFreshBeanFactory 方法

接着继续分析 AbstractRefreshableApplicationContext#obtainFreshBeanFactory 方法的处理流程:

  1. 创建实例化 DefaultLisableBeanFactory 时,会构建其父类的构造方法,其逻辑会忽略要依赖的接口
public AbstractAutowireCapableBeanFactory() {
	super();
	// 忽略要依赖的接口
	ignoreDependencyInterface(BeanNameAware.class);
	ignoreDependencyInterface(BeanFactoryAware.class);
	ignoreDependencyInterface(BeanClassLoaderAware.class);
}
  1. 指定上下文工厂对象序列化 ID
  2. customizeBeanFactory:定制 beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖
// 此方法可以交由子类去自由扩展实现
@Override
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
	super.setAllowBeanDefinitionOverriding(false);
	super.setAllowCircularReferences(false);
	super.customizeBeanFactory(beanFactory);
}
  1. loadBeanDefinitions:初始化 documentReader,并进行 XML 文件读取及解析,默认命名空间的解析,自定义标签的解析【创建 BeanDefinition 核心步骤】
XmlWebApplicationContext#loadBeanDefinitions 方法

创建配置文件读取器:XmlBeanDefinitionReader
beanDefinitionReader#setEntityResolver(new ResourceEntityResolver(this)):设置实体解析器,有 DTD(document type Definition)、XSD(XML Schema Definition) 这两种解析方式,目前大部分使用的是后者

this.dtdResolver = new BeansDtdResolver();
// 当完成这行代码的调用之后,大家神奇的发现一件事情,schemaResolver 对象的 schemaMappings 属性被完成了赋值操作,但是你遍历完成所有代码后依然没有看到显式调用
// 其实此时的原理是非常简单的,我们在进行 debug 的时候,因为在程序运行期间需要显示当前类的所有信息,所以 idea 会帮助我们调用 toString 方法,只不过此过程我们识别不到而已,idea 中可以设置关闭 Debug 模式下 toString 方法调用
// toString(){return "EntityResolver using schema mappings " + getSchemaMappings();}
// 会去加载 META-INF/spring.schemas 文件下所有键值对
this.schemaResolver = new PluggableSchemaResolver(classLoader);

initBeanDefinitionReader(beanDefinitionReader):初始化 beanDefinitionReader 对象,此处设置配置文件是否要进行验证
loadBeanDefinitions(beanDefinitionReader):开始完成对 BeanDefinition 的加载,详细流程图如下:
在这里插入图片描述
解析 spring 配置文件整体流程: 这个解析过程是由 documentLoader 完成的,从 String[]—>string—>Resource[]—>resource,最终开始将 resource 转换为 InputStream 流对象后读取成一个 document 文档,新建 BeanDefinitionDocumentReader 对象后对 XML 中 BeanDefinition 进行解析,根据文档的节点信息封装成一个个的 BeanDefinition 对象,将其包装为 BeanDefinitionHolder 对象,并把 BeanDefinition、BeanName、alias 相关信息存入【beanDefinitionMap、beanDefinitionNames】集合中.
BeanDefinitionHolder 介绍:BeanDefinition 对象持有者,封装了 BeanDefinition,bean 名字和别名,用它来完成向 IOC 容器注册,得到这个 BeanDefinitionHolder 意味着 beanDefinition 是通过 BeanDefinitionParserDelegate 对 XML 元素的信息按照 spring bean 规则进行解析得到的
通过子节点来划分整个加载 XML 配置文件的流程:

  1. createReaderContext(resource):创建 XML 上下文读取解析器,同时会加载命名空间下的 handlers,存入在【META-INF/spring.handlers】文件中,以 key(命名空间路径)—>value(具体的 handler 类)方式存储.
  2. delegate.isDefaultNamespace(root):判定命名空间是否为默认的命名空间【http://www.springframework.org/schema/beans】如果是进行默认 parseDefaultElement(ele, delegate) 处理,无须去加载文件中的命名空间 handler 类;非默认命名空间,则需要去获取对应的 handler 进行处理
  3. 默认节点标签:import、alias、bean、beans

import 标签:会获取 resource 属性值,判定其是绝对还是相对的 URI【绝对 URI 直接将 resource 对象直接重新解析的一个流程,相对 URI 则匹配上前缀路径后再走这样的一个流程】

alias:给指定的 BeanName 注册 1~N 个别名,会对所有的 alias->name 关系进行校验,如果不满足就会抛出异常结束「beanName 与 alias 相同不记录 alias、alias 已存在集合中,判定是否允许覆盖:不允许抛出异常、检查别名关系中是否出现嵌套异常,如 A->B 可以但 B->A 就不可以了、将 alias->name 键值对存入集合中」

bean 标签:获取 id、name 属性,id 作为 BeanName,name 作为 alias,如果没有指定 BeanName 名称时,那么 Spring 会根据命名规则为当前 Bean 生成 BeanName 值
checkNameUniqueness(beanName, aliases, ele):会去校验 BeanName 的唯一性,如果存在了会抛出异常
parseBeanDefinitionElement(ele, beanName, containingBean):对 bean 元素进行详细解析
1、根据 class 属性获取全路径类名,反射获取其类实例
2、解析 bean 标签内的属性:depends-on、init-method、destroy-method
3、解析 bean 标签下子标签及其属性:lookup-method【执行新的逻辑需要新加 bean】、replaced-method【将之前方法执行的逻辑替换为新的】、property、构造函数参数
4、property 标签有以下约束:property 标签上不能同时有 value 和 ref 属性、 在有 value 或 ref 属性的同时不能再有子节点、property 标签上 value 和 ref 两个属性都没有也会报错

以上流程处理完调用 BeanDefinitionReaderUtils.registerBeanDefinition(definition, registry) 注册 Bean 信息放入到 【beanDefinitionMap、beanDefinitionNames】 集合中

prepareBeanFactory

BeanFactory 准备工作,对 BeanFactory 各种属性进行填充

源码解析
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// 设置 beanFactory 的 classloader 为当前 context 的 classloader
	beanFactory.setBeanClassLoader(getClassLoader());
	// 设置 BeanFactory 表达式语言处理器
	beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
	// 为 beanFactory 增加一个默认的 propertyEditor,这个主要是对 bean 属性等设置管理的一个工具类
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

	// Configure the bean factory with context callbacks.
	// 添加 beanPostProcessor,ApplicationContextAwareProcessor 此类用来完成某些Aware对象的注入
	// postProcessBeforeInitialization 方法执行某些 Aware 对象的属性注入,实例化之后-初始化之前调用
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
	// 设置要忽略自动装配的接口,为什么此处要对这些接口进行忽略,原因非常简单,这些接口的实现是由容器通过set 方法进行注入的,
	// 所以在使用 autowire 进行注入的时候需要将这些接口进行忽略
	beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
	beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
	beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
	beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

	// BeanFactory interface not registered as resolvable type in a plain factory.
	// MessageSource registered (and found for autowiring) as a bean.
	// 设置几个自动装配的特殊规则,当在进行ioc初始化的如果有多个实现,那么就使用指定的对象进行注入
	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
	beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
	beanFactory.registerResolvableDependency(ApplicationContext.class, this);

	// Register early post-processor for detecting inner beans as ApplicationListeners.
	// 注册BPP
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

	// 增加对AspectJ的支持,在java中织入分为三种方式,分为编译器织入,类加载器织入,运行期织入,
	// 编译器织入:指在java编译器,采用特殊的编译器,将切面织入到java类中,
	// 类加载期织入:指通过特殊的类加载器,在类字节码加载到JVM时,织入切面,
	// 运行期织入:采用cglib和jdk进行切面的织入
	// aspectj 提供了两种织入方式,
	// 第一种是通过特殊编译器,在编译器,将aspectj语言编写的切面类织入到java类中,
	// 第二种是类加载期织入,就是下面的 load time weaving,此处后续讲
	if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		// Set a temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}
	// 注册默认的系统环境bean到一级缓存中
	if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
	}
	if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
	}
	if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
	}
}
  1. beanFactory#setBeanClassLoader(getClassLoader()):设置 BeanFactory 所需的类加载器【线程上下文加载器—>当前类的类加载器—>系统类加载器】
  2. beanFactory#setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())):Bean 定义值中表达式语言的解析策略,SpringBoot 默认使用的是 StandardBeanExpressionResolver
  3. beanFactory#addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())):为 BeanFactory 增加一个默认的 propertyEditor(属性编辑器)这个主要是用来管理 Bean 属性等的工具类【这个地方可以作为扩展点】
  4. beanFactory#addBeanPostProcessor(new ApplicationContextAwareProcessor(this)):新增 BPP,ApplicationContextAwareProcessor 此类用来完成某些 Aware 对象的注入,在 postProcessBeforeInitialization 方法中执行某些 Aware 属性的注入,在实例化之后、执行初始化方法之前进行调用
  5. beanFactory#ignoreDependencyInterface:设置要忽略自动装配的接口,忽略的原因非常简单,这些接口的实现是由容器通过 set 方法进行注入的,所以在使用 autowire 进行注入时需要将这些接口忽略.

EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware
还有一些 aware 接口是在执行初始化时也就是调用 invokeAwareMethods 方法时【BeanNameAware、BeanClassLoaderAware、BeanFactoryAware】进行注入.

  1. beanFactory#addBeanPostProcessor(new ApplicationListenerDetector(this)):注册 BPP,该类 ApplicationListenerDetector 作用用来检测 bean 是否实现了 ApplicationListener 接口,有两个作用,如下:
    实例化完成之后,如果 bean 是单例的并且属于 ApplicationListener 接口,则加入到多播器中
    bean 销毁之前,如果 bean 是一个 applicationListener,则从多播器中提前删除
  2. beanFactory#addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)):增加对 AspectJ 的支持,【AspectJ 提供了两种织入方式:1、通过特殊的加载器,将 aspectj 语言编写的切面类织入到 Java 类中;2、类加载器织入,就是 load time weaving】在 Java 中织入分为三种方式
    编译器织入:在 Java 编译器,采用特殊的编译器,将切面织入到 Java 类中
    类加载器织入:通过特殊的类加载器,将类字节码加载到 JVM 时,织入切面
    运行期织入:采用 CGLIB、JDK 进行切面织入
  3. beanFactory#registerSingleton【environment、systemProperties、systemEnvironment】:注册默认的系统环境 bean 到一级缓存中
扩展 BeanPostProcessor 对 Bean 进行增强

Aware 相关的在 invokeAwareMethods 方法中只会执行 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware,其他定义的 Aware 接口会在 ApplicationContextAwareProcessor.postProcessBeforeInitialization 中执行
扩展 BeanPostProcessor「简称:BPP」,其实就是实现 BPP 接口,在实现的方法编写自己需要扩展的逻辑

public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization---MyBeanPostProcessor");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization---MyBeanPostProcessor");
        if (bean instanceof Person) {
            Person person = (Person) bean;
            person.setName("哈哈哈");
            System.out.println("postProcessAfterInitialization#person:" + person.getName());
            return person;
        } else {
            return bean;
        }
    }
}

在 SpringMVC 中通过 XML 文件配置使其能够被 Spring 所读取

 <bean class="com.mashibing.MyBeanPostProcessor"/>

在 SpringBoot 中通过注解 @Configuration 或 @Import 导入该类型即可.

postProcessBeanFactory

此方法交由子类去实现做额外的处理,此处我们一般不做任何扩展工作,但是在 Web 中的代码,是由具体的实现的.

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	super.postProcessBeanFactory(beanFactory);
	// scanner=ClassPathBeanDefinitionScanner
	if (this.basePackages != null && this.basePackages.length > 0) {
		this.scanner.scan(this.basePackages);
	}
	// reader=AnnotatedBeanDefinitionReader
	if (!this.annotatedClasses.isEmpty()) {
		this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
	}
}

AnnotatedBeanDefinitionReader 类作用:直接将指定的某个没有使用 spring 提供的 @Bean 、@Component 等注解的类解析成 BeanDefinition 对象并保存到容器中,如果被解析的类上有 spring 其他注解,也会被解析,保存到 BeanDefinition 以后,后面会经过 Spring Bean 整个生命周期进行 Bean 实例构建.
ClassPathBeanDefinitionScanner 类作用:扫描指定包路径下的 @Component 注解,将有这个注解的类解析成 BeanDefinition 对象并放入容器中

invokeBeanFactoryPostProcessors

此方法是执行 BeanFactoryPostProcessor「BFPP」 方法的入口,调用各种 BeanFactory 处理器,会在这里面完成属性的 ${} 的解析工作

源码分析
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	// 获取到当前应用程序上下文的 beanFactoryPostProcessors 集合的值,并且实例化调用执行所有已经注册的 beanFactoryPostProcessor
	PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

	// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
	// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
	if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}
}

默认情况下,通过 getBeanFactoryPostProcessors 方法来获取已经注册的 BFPP,但是默认是空的,那么问题来了,如果你想扩展,怎么进行扩展工作?

  1. 新增扩展类实现 BeanFactoryPostProcessors 方法通过 XML 配置文件注入能够被 Spring 识别到,后面进行 Bean 加载「该方式配置的 Bean 不会被添加到 beanFactoryPostProcessors 集合中」
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
       System.out.println("扩展 BeanFactoryPostProcessor");
   }
}
<bean class="com.mashibing.MyBeanFactoryPostProcessor"/>
  1. 继承父类写入 super#addBeanFactoryPostProcessor 方法 「该配置引入的 Bean 会被添加进 beanFactoryPostProcessors 集合中」
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("test.xml");
ac.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
ac.refresh();

将 XML 配置的类去除即可.

实现 BFPP(BeanFactoryPostProcessor)比较重要的有这个类:ConfigurationClassPostProcessor【1、解析加了 @Configuration 的配置类;2、解析 @ComponentScan 扫描的包;3、解析 @ComponentScans 扫描的包;4、解析 @Import 注解】该类是用于 SpringBoot 自动装配过程中的核心类
ConfigurationClassPostProceesor 核心类流程详解:Spring 核心类 ConfigurationClassPostProcessor 流程讲解及源码全面分析

invokeBeanFactoryPostProcessors 执行流程

在学习分析该方法核心流程之前,我们先要区分两个类的作用,BeanFactoryPostProcessor 与 BeanDefinitionRegistryPostProcessor 区别

  • BeanFactoryPostProcessor 用于操作 BeanFactory,BeanFactory 中包含了 BeanDefinition,里面有 definitionNames、definitionMaps 两个集合
  • BeanDefinitionRegistryPostProcessor 是 BeanFactoryPostProcessor 下的子接口,它在常规 BeanFactoryPostProcessor 之前检测之前注册的 Bean 定义信息,如果一个 Bean 实现了 BeanDefinitionRegistryPostProcessor 子接口,那么它的 postProcessBeanDefinitionRegistry 方法可以和 BFPP#postProcessBeanFactory 方法一起执行
public static void invokeBeanFactoryPostProcessors(
       ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    // 无论是什么情况,优先执行 BeanDefinitionRegistryPostProcessors
    // 将已经执行过的BFPP存储在 processedBeans 中,防止重复执行
    Set<String> processedBeans = new HashSet<>();
    // 此处是 DefaultListableBeanFactory,实现了 BeanDefinitionRegistry 接口,所以为 true
    if (beanFactory instanceof BeanDefinitionRegistry) {
        // 类型转换
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        // 存放 BeanFactoryPostProcessor 的集合
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
        // 存放 BeanDefinitionRegistryPostProcessor 的集合
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
        // 首先处理入参中的 beanFactoryPostProcessors,遍历所有的 beanFactoryPostProcessors,将BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor 区分开
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            // 如果是 BeanDefinitionRegistryPostProcessor
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                BeanDefinitionRegistryPostProcessor registryProcessor =
                        (BeanDefinitionRegistryPostProcessor) postProcessor;
                // 直接执行 BeanDefinitionRegistryPostProcessor 接口中的postProcessBeanDefinitionRegistry 方法
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                // 添加到 registryProcessors,用于后续执行 postProcessBeanFactory 方法
                registryProcessors.add(registryProcessor);
            } else {
                // 否则,只是普通的BeanFactoryPostProcessor,添加到regularPostProcessors,用于后续执行postProcessBeanFactory方法
                regularPostProcessors.add(postProcessor);
            }
        }
        // 用于保存本次要执行的 BeanDefinitionRegistryPostProcessor
        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
        // 调用所有实现PriorityOrdered接口的BeanDefinitionRegistryPostProcessor实现类
        // 找到所有实现BeanDefinitionRegistryPostProcessor接口bean的beanName
        String[] postProcessorNames =
               beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        // 遍历处理所有符合规则的postProcessorNames
        for (String ppName : postProcessorNames) {
            // 检测是否实现了 PriorityOrdered 接口
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                // 获取名字对应的bean实例,添加到currentRegistryProcessors中
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                // 将要被执行的BFPP名称添加到processedBeans,避免后续重复执行
                processedBeans.add(ppName);
            }
        }
        // 按照优先级进行排序操作
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        // 添加到registryProcessors中,用于最后执行postProcessBeanFactory方法
        registryProcessors.addAll(currentRegistryProcessors);
        // 遍历currentRegistryProcessors,执行postProcessBeanDefinitionRegistry方法
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        // 执行完毕之后,清空currentRegistryProcessors
        currentRegistryProcessors.clear();
        // 找到所有实现BeanDefinitionRegistryPostProcessor接口bean的beanName,此处需要重复查找的原因在于上面的执行过程中可能会新增其他的 BeanDefinitionRegistryPostProcessor
        // 在 MyBeanDefinitionRegistryPostProcessor 类实现新增
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            // 检测是否实现了Ordered接口,并且还未执行过
            if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                // 获取名字对应的bean实例,添加到currentRegistryProcessors中
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                // 将要被执行的BFPP名称添加到processedBeans,避免后续重复执行
                processedBeans.add(ppName);
            }
        }
        // 按照优先级进行排序操作
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        // 添加到registryProcessors中,用于最后执行postProcessBeanFactory方法
        registryProcessors.addAll(currentRegistryProcessors);
        // 遍历currentRegistryProcessors,执行postProcessBeanDefinitionRegistry方法
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        // 执行完毕之后,清空currentRegistryProcessors
        currentRegistryProcessors.clear();
        // 最后,调用所有剩下的BeanDefinitionRegistryPostProcessors
        boolean reiterate = true;
        while (reiterate) {
            reiterate = false;
            // 找出所有实现BeanDefinitionRegistryPostProcessor接口的类
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            // 遍历执行
            for (String ppName : postProcessorNames) {
                // 跳过已经执行过的BeanDefinitionRegistryPostProcessor
                if (!processedBeans.contains(ppName)) {
                    // 获取名字对应的bean实例,添加到currentRegistryProcessors中
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    // 将要被执行的BFPP名称添加到processedBeans,避免后续重复执行
                    processedBeans.add(ppName);
                    reiterate = true;
                }
            }
            // 按照优先级进行排序操作
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            // 添加到registryProcessors中,用于最后执行postProcessBeanFactory方法
            registryProcessors.addAll(currentRegistryProcessors);
            // 遍历currentRegistryProcessors,执行postProcessBeanDefinitionRegistry方法
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            // 执行完毕之后,清空currentRegistryProcessors
            currentRegistryProcessors.clear();
        }
        // 调用所有BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法
        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
        // 最后,调用入参beanFactoryPostProcessors中的普通BeanFactoryPostProcessor的postProcessBeanFactory方法
        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    } else {
        // Invoke factory processors registered with the context instance.
        // 如果beanFactory不归属于BeanDefinitionRegistry类型,那么直接执行postProcessBeanFactory方法
        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }
    // 到这里为止,入参 beanFactoryPostProcessors 和容器中的所有BeanDefinitionRegistryPostProcessor 已经全部处理完毕,下面开始处理容器中所有的 BeanFactoryPostProcessor
    // 可能会包含一些实现类,只实现了 BeanFactoryPostProcessor,并没有实现 BeanDefinitionRegistryPostProcessor 接口
    // 找到所有实现BeanFactoryPostProcessor接口的类
    // 自身 new 出来的 BFPP 无法匹配到,只会匹配到交由 Bean 容器管理的对象
    String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
    // 用于存放实现了PriorityOrdered接口的BeanFactoryPostProcessor
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    // 用于存放实现了Ordered接口的BeanFactoryPostProcessor的beanName
//		List<String> orderedPostProcessorNames = new ArrayList<>();
    List<BeanFactoryPostProcessor> orderedPostProcessor = new ArrayList<>();
    // 用于存放普通BeanFactoryPostProcessor的beanName
//		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    List<BeanFactoryPostProcessor> nonOrderedPostProcessorNames = new ArrayList<>();
    // 遍历 postProcessorNames,将 BeanFactoryPostProcessor 按实现 PriorityOrdered、实现Ordered 接口、普通三种区分开
    for (String ppName : postProcessorNames) {
        // 跳过已经执行过的BeanFactoryPostProcessor
        if (processedBeans.contains(ppName)) {
            // skip - already processed in first phase above
        }
        // 添加实现了PriorityOrdered接口的BeanFactoryPostProcessor到priorityOrderedPostProcessors
        else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
        }
        // 添加实现了Ordered接口的BeanFactoryPostProcessor的beanName到orderedPostProcessorNames
        else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
//				orderedPostProcessorNames.add(ppName);
            orderedPostProcessor.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
        } else {
            // 添加剩下的普通BeanFactoryPostProcessor的beanName到nonOrderedPostProcessorNames
//				nonOrderedPostProcessorNames.add(ppName);
            nonOrderedPostProcessorNames.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
        }
    }
    // 对实现了PriorityOrdered接口的BeanFactoryPostProcessor进行排序
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    // 遍历实现了 PriorityOrdered 接口的 BeanFactoryPostProcessor,执行 postProcessBeanFactory 方法
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
    // 创建存放实现了Ordered接口的BeanFactoryPostProcessor集合
//		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
    // 遍历存放实现了Ordered接口的BeanFactoryPostProcessor名字的集合
//		for (String postProcessorName : orderedPostProcessorNames) {
    // 将实现了Ordered接口的BeanFactoryPostProcessor添加到集合中
//			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
//		}
    // 对实现了Ordered接口的BeanFactoryPostProcessor进行排序操作
    sortPostProcessors(orderedPostProcessor, beanFactory);
    // 遍历实现了Ordered接口的BeanFactoryPostProcessor,执行postProcessBeanFactory方法
//		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(orderedPostProcessor, beanFactory);

    // Finally, invoke all other BeanFactoryPostProcessors.
    // 最后,创建存放普通的BeanFactoryPostProcessor的集合
//		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
    // 遍历存放实现了普通BeanFactoryPostProcessor名字的集合
//		for (String postProcessorName : nonOrderedPostProcessorNames) {
    // 将普通的BeanFactoryPostProcessor添加到集合中
//			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
//		}
    // 遍历普通的BeanFactoryPostProcessor,执行postProcessBeanFactory方法
//		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessorNames, beanFactory);
    // 清除元数据缓存(mergeBeanDefinitions、allBeanNamesByType、singletonBeanNameByType)
    // 因为后置处理器可能已经修改了原始元数据,例如,替换值中的占位符
    beanFactory.clearMetadataCache();
}

源码中 PriorityOrdered、Ordered、nonOrdered 的 BFPP 对象,都分别用不同的循环进行遍历 getBean,此处调整了源码,将这三种类型的对象放在一个循环里面进行处理,增加多重 if 判别存入到不同的集合中
以下对源码中的流程进行流程图的解析,以及详细的文档说明
在这里插入图片描述

  • 创建一个空的集合,用来存储已经执行过的 BFPP 或 BDRPP

  • 判断当前 BeanFactory 是否是 BeanDefinitionRegistry 类型,此处是 DefaultListableBeanFactory,实现了 BeanDefinitionRegistry 接口,所以为 true

  • 创建两个集合用于存放不同的接口,分别是存储 BFPP(BeanFactoryPostProcessor)接口的 regularPostProcessors,另外一个是 存储 BDRPP(BeanDefinitionRegistryPostProcessor)接口的 registryProcessors;存储到这两个集合中的类只是为了方便执行 BFPP 下的 postProcessBeanFactory 方法
    在这里插入图片描述

  • 先处理用户自定义的 BFPP 集合,遍历每一个元素,先判定其是否为 BDRPP 类型:如果是就执行 postProcessBeanDefinitionRegistry 方法并将其添加进 registryProcessors 集合中;如果不是就将其添加进 regularPostProcessors 即可

  • 单独创建一个集合对象,用于存放当前需要执行的 BDRPP 对象:currentRegistryProcessors

  • 获取当前容器中实现了 BDRPP 接口的 beanName
    1、判定是否存在实现了 PriorityOrdered 接口的 beanName:如果有就通过 beanName 进行 getBean 操作【getBean->doGetBean->createBean->doCreateBean】,将其添加进 currentRegistryProcessors 集合中,再添加到 processedBeans 集合中【避免后续重复执行】
    2、判断是否存在实现了 Ordered 接口的 beanName:如果有就通过 beanName 进行 getBean 操作【getBean->doGetBean->createBean->doCreateBean】,将其添加进 currentRegistryProcessors 集合中,再添加到 processedBeans 集合中【避免后续重复执行】
    3、找出剩下所有实现 BDRPP 接口的类,直至所有的方法所被找到并且执行完毕
    4、1-2-3 步骤取出对应的接口出来以后,都要经过如下的流程去处理

    • 对 currentRegistryProcessors 进行排序
    • registryProcessors 将 currentRegistryProcessors 所有元素添加进去
    • 遍历调用且执行 currentRegistryProcessors 集合每一个元素的 postProcessBeanDefinitionRegistry 方法
    • 清空 currentRegistryProcessors,避免重复添加,方便下面新增

    5、调用所有 BeanDefinitionRegistryPostProcessor#postProcessBeanFactory 方法
    6、最后,调用入参 beanFactoryPostProcessors 中的普通 BeanFactoryPostProcessor#postProcessBeanFactory 方法
    7、到这里为止,入参中所有的 BFPP 和容器中所有的 BDRPP 都已经全部处理完毕

以下的流程是处理容器中的 BFPP 接口
处理容器中的 BFPP【自身 new 出来的入参时会携带进来,下面的都是被容器所管理的 BFPP】
在这里插入图片描述

  • 判定是否是实现 PriorityOrdered 接口的 beanName,如果是将其放入 priorityOrderedPostProcessors 集合中
  • 判定是否是实现 Ordered 接口的 beanName,如果是将其放入 Ordered 对应的集合中
  • 如果以上两者都不是,存入到另外一个集合中
  • 按照以上三点的先后顺序,对各自的集合先进行排序(nonOrdered 元素不需要进行排序),对集合进行遍历且调用具体的 postProcessBeanFactory 方法执行
扩展 BeanDefinitionRegistryPostProcessor

实现 BDRPP 接口的类可以调用 registry.registerBeanDefinition 来新增 BeanDefinition 信息,配置它的同时新增的类也可以被 Spring 被所识别

// 该类需要在 XML 配置,使其能够让 Spring 识别
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("执行postProcessBeanDefinitionRegistry---MyBeanDefinitionRegistryPostProcessor");
        // 引入了一个新的 BDRPP 实现类
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(MySelfBeanDefinitionRegistryPostProcessor.class);
        builder.addPropertyValue("name","zhangsan");
        registry.registerBeanDefinition("vnjohn",builder.getBeanDefinition());
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("执行postProcessBeanFåactory---MyBeanDefinitionRegistryPostProcessor");
        BeanDefinition msb = beanFactory.getBeanDefinition("vnjohn");
        msb.getPropertyValues().getPropertyValue("name").setConvertedValue("lisi");
        System.out.println("===============");
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
// 该类不需要进行配置,会在循环查找 BDRPP 时被找到
public class MySelfBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        
        System.out.println("调用执行postProcessBeanDefinitionRegistry--MySelfBeanDefinitionRegistryPostProcessor");
        // 这里可以继续进行扩展新增 BDRPP 实现类
        // BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(MySelfTwoBeanDefinitionRegistryPostProcessor.class);
        // builder.addPropertyValue("nickName","vnjohn");
        // registry.registerBeanDefinition("mySelfTwo",builder.getBeanDefinition());
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("调用执行postProcessBeanFactory--MySelfBeanDefinitionRegistryPostProcessor");
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
<bean class="com.mashibing.selfbdrpp.MyBeanDefinitionRegistryPostProcessor"/>

总结

由于 refresh 涉及到了 13 个方法,在一篇文章里进行分解内容会过长,分为两个章节,剩下的 registerBeanPostProcessors、initMessageSource、initApplicationEventMulticaster、onRefresh、registerListeners、finishBeanFactoryInitialization、finishRefresh 方法在章节二进行剖析

记录个人在学习 Spring 源码时整理出来的详细笔记,整理文章不易,喜欢的可以点个关注和赞👍哦,不喜勿喷!

更多技术文章可以查看:vnjohn 个人博客

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

vnjohn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值