Spring 源码学习~12、容器的拓展功能简介

容器的拓展功能简介

一、简介

ApplicationContext 和 BeanFactory 两者都是用于加载 bean 的,相比之下,ApplicationContext 除了包含 BeanFactory 的所有功能之外,还提供了更多的扩展功能。

那么 ApplicationContext 比 BeanFactory 多出了哪些功能呢?

写法上的不同:

BeanFactory

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring/app-context.xml"));
TestBean testBean = (TestBean) beanFactory.getBean("testBean");
System.out.println(testBean);

ApplicationContext

ApplicationContext bf = new ClassPathXmlApplicationContext("spring/app-context.xml");
TestBean testBean1 = (TestBean)bf.getBean("testBean");
System.out.println(testBean1);

下面我们以 ClassPathXmlApplicationContext 为切入点,来对整体功能进行分析。

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
    this(new String[]{configLocation}, true, (ApplicationContext)null);
}

public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
    this(configLocations, true, (ApplicationContext)null);
}

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
    super(parent);
    this.setConfigLocations(configLocations);
    if (refresh) {
        this.refresh();
    }

}

可以看到首先是设置路径,然后解析和功能的实现都在 refresh() 中实现。

二、设置配置路径

ClassPathXmlApplicationContext 支持多个配置文件以数组的形式同时传入:

public void setConfigLocations(@Nullable String... locations) {
    if (locations != null) {
        Assert.noNullElements(locations, "Config locations must not be null");
        this.configLocations = new String[locations.length];

        for(int i = 0; i < locations.length; ++i) {
            //解析给定路径
            this.configLocations[i] = this.resolvePath(locations[i]).trim();
        }
    } else {
        this.configLocations = null;
    }

}

如果数组中包含特殊符号,如${var},那么在 resolvePath 中会搜寻匹配的系统变量进行替换。

三、核心方法 refresh 简介

设置路径之后,便可以根据路径对配置文件进行解析,以及各种功能的实现了,我们来分析 refresh() 函数。

public void refresh() throws BeansException, IllegalStateException {
    synchronized(this.startupShutdownMonitor) {
        StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
        //准备刷新的上下文环境
        this.prepareRefresh();
        //初始化 beanFactory,并进行 XML 文件读取
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
        //对 beanFactory 进行各种功能填充
        this.prepareBeanFactory(beanFactory);

        try {
            //子类覆盖方法做额外处理
            this.postProcessBeanFactory(beanFactory);
            StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
            
            //激活各种 BeanFactory 处理器
            this.invokeBeanFactoryPostProcessors(beanFactory);
            
            //注册拦截 Bean 创建时的后置处理器,这里只是注册,真正的调用是在 getBean 的时候
            this.registerBeanPostProcessors(beanFactory);
            beanPostProcess.end();
            //为上下文初始化 Message 源,即不同语言的消息体,国际化处理
            this.initMessageSource();
            
            //初始化应用消息广播器,并放入 “ApplicationEventMulticaster” bean 中
            this.initApplicationEventMulticaster();
            
            //留给子类来初始化其他的 bean
            this.onRefresh();
            
            //在所有注册的 bean 中查找 Listener bean,注册到消息广播器中
            this.registerListeners();
            
            //初始化剩下的单实例(非惰性的)
            this.finishBeanFactoryInitialization(beanFactory);
            
            //完成刷新过程,通知声明周期处理器 lifecycleProcessor 刷新过程,同时发出
            //ContextRefreshEvent 通知别人
            this.finishRefresh();
        } catch (BeansException var10) {
            if (this.logger.isWarnEnabled()) {
                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
            }

            //出异常,销毁所有 bean
            this.destroyBeans();
            //取消刷新
            this.cancelRefresh(var10);
            throw var10;
        } finally {
            //重置缓存
            this.resetCommonCaches();
            contextRefresh.end();
        }

    }
}

下面概括一下 ClassPathXmlApplicationContext 初始化的步骤:

  • 1、初始化前的准备工作。如:对系统属性或环境变量进行准备及验证
  • 2、初始化 BeanFactory,并进行 XML 文件读取。
  • 3、对 BeanFactory 进行各种功能填充。
    • @Qualifier 和 @Autowired 正是在这一步骤中增加的支持。
  • 4、子类覆盖方法做额外处理。
    • Spring 中随处可见到一些可拓展的空函数,如 postProcessBeanFactory 函数可以方便程序员在业务上做进一步的拓展。
  • 5、激活各种 BeanFactory 处理器。
  • 6、注册拦截 bean 创建的 bean 处理器,这里只是注册,真正的调用是在 getBean 的时候
  • 7、为上下文初始化 Message 源,即不同语言的消息体,国际化处理
  • 8、初始化应用消息广播器,并放入 “ApplicationEventMulticaster” bean 中
  • 9、留给子类来初始化其他的 bean
  • 10、在所有注册的 bean 中查找 Listener bean,注册到消息广播器中
  • 11、初始化剩下的单实例(非惰性的)
  • 12、完成刷新过程,通知声明周期处理器 lifecycleProcessor 刷新过程,同时发出 ContextRefreshEvent 通知别人

接下来具体分析下每个步骤的具体功能。

四、环境准备

prepareRefresh 函数主要是做些准备工作,例如对系统属性及环境变量的初始化及验证。

protected void prepareRefresh() {
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);
    if (this.logger.isDebugEnabled()) {
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Refreshing " + this);
        } else {
            this.logger.debug("Refreshing " + this.getDisplayName());
        }
    }

    //留给子类覆盖
    this.initPropertySources();
    //验证需要的属性文件是否已经放入到环境中
    this.getEnvironment().validateRequiredProperties();
    if (this.earlyApplicationListeners == null) {
        this.earlyApplicationListeners = new LinkedHashSet(this.applicationListeners);
    } else {
        this.applicationListeners.clear();
        this.applicationListeners.addAll(this.earlyApplicationListeners);
    }

    this.earlyApplicationEvents = new LinkedHashSet();
}

咋一看这个步骤好像没什么作用,因为 initPropertySources() 是空函数,this.getEnvironment().validateRequiredProperties() 也因为没有验证的属性而没有做任何处理。但是如果这个函数用好了,作用还是很大的,我们需要来探讨下怎么使用它?首先我们研究下这个函数里面各个步骤的作用。

  • 1、initPropertySources 符合开放式结构设计,给用户最大扩展 Spring 的能力。用户可以根据自身的需要重写 initPropertySources 方法,并在方法中进行个性化的属性处理及设置。
  • 2、validateRequiredProperties 是对属性进行验证。

我们举例说明 validateRequiredProperties 的验证功能。

**场景描述:**工程运行过程中用到的某个设置(例如 VAR)是从系统环境变量中取得的,而如果用户没有在系统环境变量中配置这个参数,那么工程不会工作。这样的场景下,我们可以自定义类:

package com.luo.spring.guides.helloworld.applicationcontext.validate.required;

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/11/29 16:03
 * @description :
 */
public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {

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

    @Override
    protected void initPropertySources() {
        //添加验证要求
        getEnvironment().setRequiredProperties("VAR");
    }
}

测试

package com.luo.spring.guides.helloworld.applicationcontext.validate.required;

import com.luo.spring.guides.helloworld.common.TestBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/11/29 16:07
 * @description :
 */
public class Main {

    public static void main(String[] args) {
        ApplicationContext bf = new MyClassPathXmlApplicationContext("spring/app-context.xml");
        TestBean testBean1 = (TestBean)bf.getBean("testBean");
        System.out.println(testBean1);
    }
}

//输出 Exception in thread "main" org.springframework.core.env.MissingRequiredPropertiesException: The following properties were declared as required but could not be resolved: [VAR]

五、加载 BeanFactory

obtainFreshBeanFactory 是实现 BeanFactory 的地方,经过此函数后,ApplicationContext 就包含了 BeanFactory 的全部功能了。

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

protected final void refreshBeanFactory() throws BeansException {
    if (this.hasBeanFactory()) {
        this.destroyBeans();
        this.closeBeanFactory();
    }

    try {
        //创建 DefaultListableBeanFactory
        DefaultListableBeanFactory beanFactory = this.createBeanFactory();
        
        //为了序列化指定 id,如果需要的话,让 BeanFactory 从 id 反序列化到 BeanFactory 对象
        beanFactory.setSerializationId(this.getId());
        
        //定制 BeanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象、循环依赖
        this.customizeBeanFactory(beanFactory);
        //初始化 DocumentReader,并进行 XML 文件读取及解析
        this.loadBeanDefinitions(beanFactory);
        this.beanFactory = beanFactory;
    } catch (IOException var2) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var2);
    }
}

我们详细分析上面每个步骤。

  • 1、创建 DefaultListableBeanFactory。
    • 之前使用的 XmlBeanFactory 继承自 DefaultListableBeanFactory,并提供了 XmlBeanDefinitionReader 类型的 reader 属性,所以 DefaultListableBeanFactory 是基础,这里就首先实例化。
  • 2、指定序列化 ID
  • 3、定制 BeanFactory。
  • 4、加载 BeanDefinition。
  • 5、使用全局变量记录 BeanFactory 类实例。

1、定制 BeanFactory

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
    //如果属性 allowBeanDefinitionOverriding 不为 null,设置给 beanFactory 对象相应属性,
    //此属性含义:是否允许覆盖同名称的不同定义的对象
    if (this.allowBeanDefinitionOverriding != null) {
        beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
    
    //如果属性 allowCircularReferences 不为 null,设置给 beanFactory 对象相应属性,
    //此属性含义:是否允许 bean 之间存在循环依赖
    if (this.allowCircularReferences != null) {
        beanFactory.setAllowCircularReferences(this.allowCircularReferences);
    }
}

想要实现相应的设置,可以自己在实现的子类中使用方法覆盖:

package com.luo.spring.guides.helloworld.applicationcontext.validate.required;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/11/29 16:03
 * @description :
 */
public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {

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

    @Override
    protected void initPropertySources() {
        //添加验证要求
        getEnvironment().setRequiredProperties("VAR");
    }

    @Override
    protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
        super.setAllowBeanDefinitionOverriding(false);
        super.setAllowCircularReferences(false);
        super.customizeBeanFactory(beanFactory);
    }
}

2、加载 BeanDefinition

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // Create a new XmlBeanDefinitionReader for the given BeanFactory.
    //为指定 BeanFactory 创建 XmlBeanDefinitionReader
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    // Configure the bean definition reader with this context's
    // resource loading environment.
    //对 beanDefinitionReader 进行环境变量的设置
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    // Allow a subclass to provide custom initialization of the reader,
    // then proceed with actually loading the bean definitions.
    //对 BeanDefinitionReader 进行设置,可以被子类覆盖
    initBeanDefinitionReader(beanDefinitionReader);
    loadBeanDefinitions(beanDefinitionReader);
}

在初始化 DefaultListableBeanFactory 和 XmlBeanDefinitionReader 后,就可以进行配置文件的读取了。

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
        reader.loadBeanDefinitions(configResources);
    }
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        reader.loadBeanDefinitions(configLocations);
    }
}

到 XmlBeanDefinitionReader#loadBeanDefinitions 这一步,就到之前我们分析 XmlBeanFactory 解析配置文件的步骤了,这里不再赘述。

六、功能扩展

进入 prepareBeanFactory 前,Spring 已经完成了对配置的解析,而 ApplicationContext 在功能上的扩展也由此展开。

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // Tell the internal bean factory to use the context's class loader etc.
    //设置 beanFactory 的 classLoader 为当前 context 的classLoader
    beanFactory.setBeanClassLoader(getClassLoader());
    if (!shouldIgnoreSpel) {
        //设置 beanFactory 的表达式语言处理器,Spring 3 增加了表达式语言的支持
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    }
    //为 beanFactory 增加一个默认的 PropertyEditor,这个主要是对 bean 的属性等设置管理的一个工具
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // Configure the bean factory with context callbacks.
    //增加 BeanPostProcessor
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    
    //设置几个忽略自动装配的接口
    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.ignoreDependencyInterface(ApplicationStartupAware.class);

    // BeanFactory interface not registered as resolvable type in a plain factory.
    // MessageSource registered (and found for autowiring) as a bean.
    //设置几个自动装配的特殊规则
    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.
    //将用于检测内部 bean 的早期后处理器注册为 ApplicationListeners。
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // Detect a LoadTimeWeaver and prepare for weaving, if found.
    //检测 LoadTimeWeaver 和 增加对 AspectJ 的支持
    if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        // Set a temporary ClassLoader for type matching.
        //为类型匹配设置一个临时的ClassLoader。
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // Register default environment beans.
    //注册默认的系统环境系列的 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());
    }
    if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
        beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
    }
}

上面函数主要增加了如下拓展:

  • 1、增加对 SpEl 语言的支持。
  • 2、增加对属性编辑器的支持
  • 3、增加对一些内置类,比如 EnvironmentAware、MessageSourceAware 的信息注入的支持。
  • 4、设置了依赖功能可忽略的接口。
  • 5、注册一些固定依赖的属性。
  • 6、增加对 AspectJ 的支持。
  • 7、将相关环境变量即属性注册以单例模式注册。

1、增加对 SpEl 语言的支持

beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

Spring 表达式语言全称为 Spring Expression Language,简称 SpEl。它能在运行时构建复杂表达式、存取对象图属性、对象方法调用等,并且能与 Spring 功能完美整合(比如用来配置 bean 定义)。SpEL 是单独的模块,只依赖于 core 模块。可以单独使用。

示例


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="testBean" class="com.luo.spring.guides.common.TestBean"/>

    <bean id="spelTestBean" class="com.luo.spring.guides.spel.SpelTestBean">
        <property name="testBean" value="#{testBean}"/>
    bean>
beans>

等价于


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="testBean" class="com.luo.spring.guides.common.TestBean"/>

    <bean id="spelTestBean" class="com.luo.spring.guides.spel.SpelTestBean">
        <property name="testBean" ref="testBean"/>
    bean>
beans>

源码中是通过 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())) 来注册语言解析器。

注册完后是什么时候调用此解析器来解析的呢?Spring 中在 bean 进行初始化的时候会有属性填充这一步,这一步中的 AbstractAutowireCapableBeanFactory 类的 applyPropertyValues 函数就是用来完成这个调用解析器解析的功能的。具体源码是在下面这一步:

@Nullable
protected Object evaluateBeanDefinitionString(@Nullable String value, @Nullable BeanDefinition beanDefinition) {
    if (this.beanExpressionResolver == null) {
        return value;
    }

    Scope scope = null;
    if (beanDefinition != null) {
        String scopeName = beanDefinition.getScope();
        if (scopeName != null) {
            scope = getRegisteredScope(scopeName);
        }
    }
    return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
}

2、增加属性注册编辑器

beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

Spring DI 注入的时候,像 Date 类型的属性因为无法识别,是注入不进来的,因为 Java 类中的属性是 Date 类型,但是 XML 中的配置确实 String 类型,所以会报异常。

Spring 针对此问题提供了两种解决方案。

1)、使用自定义属性编辑器

a、编写自定义属性编辑器

package com.luo.spring.guides.propertyeditor.custom;

import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DatePropertyEditor extends PropertyEditorSupport  {
    private String format = "yyyy-MM-dd";

    public void setFormat(String format) {
        this.format = format;
    }

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        SimpleDateFormat dateFormatter = new SimpleDateFormat(format);
        try {
            Date d = dateFormatter.parse(text);
            this.setValue(d);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

2、将自定义属性编辑器注册到 Spring 中



<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

        <bean name="customEditorConfigurer"
              class="org.springframework.beans.factory.config.CustomEditorConfigurer">
            <property name="customEditors">
                <map>
                    <entry key="java.util.Date">
                        <bean class="com.luo.spring.guides.propertyeditor.custom.DatePropertyEditor">
                            <property name="format" value="yyyy-MM-dd"/>
                        bean>
                    entry>
                map>
            property>
        bean>
beans>

2)、注册 Spring 自带的属性编辑器 CustomDateEditor

1、定义属性编辑器

package com.luo.spring.guides.propertyeditor.custom;

import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.propertyeditors.CustomDateEditor;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author : archer
 * @date : Created in 2022/12/16 15:17
 * @description :
 */
public class DatePropertyEditorRegistrar implements PropertyEditorRegistrar {
    @Override
    public void registerCustomEditors(PropertyEditorRegistry registry) {
        SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
        registry.registerCustomEditor(Date.class,
                new CustomDateEditor(dateFormatter, true));
    }
}

2、注册到 Spring 中



<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer" >
        <property name="propertyEditorRegistrars">
            <list>
                <bean class="com.luo.spring.guides.propertyeditor.custom.DatePropertyEditorRegistrar"/>
            list>
        property>
    bean>
beans>

3)、源码分析

ResourceEditorRegistrar#registerCustomEditors

@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
    ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
    doRegisterEditor(registry, Resource.class, baseEditor);
    doRegisterEditor(registry, ContextResource.class, baseEditor);
    doRegisterEditor(registry, WritableResource.class, baseEditor);
    doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
    doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
    doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
    doRegisterEditor(registry, Path.class, new PathEditor(baseEditor));
    doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor));
    doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));

    ClassLoader classLoader = this.resourceLoader.getClassLoader();
    doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
    doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
    doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));

    if (this.resourceLoader instanceof ResourcePatternResolver) {
        doRegisterEditor(registry, Resource[].class,
                         new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader, this.propertyResolver));
    }
}

/**
	 * Override default editor, if possible (since that's what we really mean to do here);
	 * otherwise register as a custom editor.
	 */
private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
    if (registry instanceof PropertyEditorRegistrySupport) {
        ((PropertyEditorRegistrySupport) registry).overrideDefaultEditor(requiredType, editor);
    }
    else {
        registry.registerCustomEditor(requiredType, editor);
    }
}

doRegisterEditor 函数中,可以看到上面提到的自定义属性中使用的关键代码。ResourceEditorRegistrar#registerCustomEditors 只是注册了一系列常用类型的属性编辑器。但是 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); 仅仅是注册了 ResourceEditorRegistrar 类的实例,并没有调用ResourceEditorRegistrar#registerCustomEditors 方法进行注册,那到底是什么时候注册的呢?

我们查看下 ResourceEditorRegistrar#registerCustomEditors 的调用链,可以追踪到 AbstractBeanFactory#initBeanWrapper 方法,这是在 bean 初始化时使用的一个方法,前面已经分析过了,getBean 的时候会有调用。主要是在将 BeanDefinition 转换为 BeanWrapper 后用于对属性的填充。到此,逻辑上已经很清晰了,bean 初始化后会调用 ResourceEditorRegistrar#registerCustomEditors 方法进行鼻梁的通用属性编辑器注册,注册后,在属性填充环节,便可让 Spring 使用这些编辑器进行属性的解析了。

BeanWrapper 用于封装 bean,它间接继承了 PropertyEditorRegistry 类型,BeanWrapper 的默认实现类型是 BeanWrapperImpl,BeanWrapperImpl 除了实现 BeanWrapper 接口外还继承了 PropertyEditorRegistrySupport。在 PropertyEditorRegistrySupport 中有这样一个方法:

private void createDefaultEditors() {
    this.defaultEditors = new HashMap<>(64);

    // Simple editors, without parameterization capabilities.
    // The JDK does not contain a default editor for any of these target types.
    this.defaultEditors.put(Charset.class, new CharsetEditor());
    this.defaultEditors.put(Class.class, new ClassEditor());
    this.defaultEditors.put(Class[].class, new ClassArrayEditor());
    this.defaultEditors.put(Currency.class, new CurrencyEditor());
    this.defaultEditors.put(File.class, new FileEditor());
    this.defaultEditors.put(InputStream.class, new InputStreamEditor());
    if (!shouldIgnoreXml) {
        this.defaultEditors.put(InputSource.class, new InputSourceEditor());
    }
    this.defaultEditors.put(Locale.class, new LocaleEditor());
    this.defaultEditors.put(Path.class, new PathEditor());
    this.defaultEditors.put(Pattern.class, new PatternEditor());
    this.defaultEditors.put(Properties.class, new PropertiesEditor());
    this.defaultEditors.put(Reader.class, new ReaderEditor());
    this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor());
    this.defaultEditors.put(TimeZone.class, new TimeZoneEditor());
    this.defaultEditors.put(URI.class, new URIEditor());
    this.defaultEditors.put(URL.class, new URLEditor());
    this.defaultEditors.put(UUID.class, new UUIDEditor());
    this.defaultEditors.put(ZoneId.class, new ZoneIdEditor());

    // Default instances of collection editors.
    // Can be overridden by registering custom instances of those as custom editors.
    this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class));
    this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));
    this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class));
    this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));
    this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class));

    // Default editors for primitive arrays.
    this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());
    this.defaultEditors.put(char[].class, new CharArrayPropertyEditor());

    // The JDK does not contain a default editor for char!
    this.defaultEditors.put(char.class, new CharacterEditor(false));
    this.defaultEditors.put(Character.class, new CharacterEditor(true));

    // Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor.
    this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false));
    this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true));

    // The JDK does not contain default editors for number wrapper types!
    // Override JDK primitive number editors with our own CustomNumberEditor.
    this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false));
    this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true));
    this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false));
    this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true));
    this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false));
    this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true));
    this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false));
    this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true));
    this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false));
    this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));
    this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false));
    this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true));
    this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));
    this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));

    // Only register config value editors if explicitly requested.
    if (this.configValueEditorsActive) {
        StringArrayPropertyEditor sae = new StringArrayPropertyEditor();
        this.defaultEditors.put(String[].class, sae);
        this.defaultEditors.put(short[].class, sae);
        this.defaultEditors.put(int[].class, sae);
        this.defaultEditors.put(long[].class, sae);
    }
}

它的作用一目了然,就是定义了一些常用的属性编辑器,并自动注册,如果我们定义的 bean 中的某个属性类型不在上面的常用配置中,我们就需要进行个性化属性编辑器的注册。

3、添加 ApplicationContextBeanPostProcessor 处理器

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

这里是注册 ApplicationContextAwareProcessor,真正的处理逻辑在 ApplicationContextAwareProcessor 类中。在 bean 实例化的时候,即 Spring 激活 bean 的 init-method 的前后,会调用 BeanPostProcessor 的 postProcessBeforeInitialization 和 postProcessAfterInitialization 方法。ApplicationContextAwareProcessor 没有对 postProcessAfterInitialization 做什么逻辑,所以我们重点分析 postProcessBeforeInitialization 方法。

@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
          bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
          bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
          bean instanceof ApplicationStartupAware)) {
        return bean;
    }

    AccessControlContext acc = null;

    if (System.getSecurityManager() != null) {
        acc = this.applicationContext.getBeanFactory().getAccessControlContext();
    }

    if (acc != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareInterfaces(bean);
            return null;
        }, acc);
    }
    else {
        invokeAwareInterfaces(bean);
    }

    return bean;
}


private void invokeAwareInterfaces(Object bean) {
    if (bean instanceof EnvironmentAware) {
        ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
    }
    if (bean instanceof EmbeddedValueResolverAware) {
        ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
    }
    if (bean instanceof ResourceLoaderAware) {
        ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
    }
    if (bean instanceof ApplicationEventPublisherAware) {
        ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
    }
    if (bean instanceof MessageSourceAware) {
        ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
    }
    if (bean instanceof ApplicationStartupAware) {
        ((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
    }
    if (bean instanceof ApplicationContextAware) {
        ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
    }
}

postProcessBeforeInitialization 方法中调用了 invokeAwareInterfaces 方法。invokeAwareInterfaces 方法的逻辑很明显,实现了这些 aware 的 bean,可以在初始化之后,获取相对应的资源。

4、设置忽略依赖

Spring 将 ApplicationContextAwareProcessor 注册后,其 invokeAwareInterfaces 方法内间接调用的 Aware 类已经不是普通的 bean 了。因此需要在依赖注入的时候,将它们忽略。

//设置几个忽略自动装配的接口
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.ignoreDependencyInterface(ApplicationStartupAware.class);

5、注册依赖

有了忽略依赖,也会有注册依赖的功能。当注册了依赖解析后,后面进行 bean 的属性注入的时候,一旦检测到属性为注册过的依赖类型,便会将此事保存的实例,注册进去。

//设置几个自动装配的特殊规则
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

七、BeanFactory 的后置处理

BeanFactory 作为 Spring 容器功能的基础,用于存放所有已加载的 bean,为了保证扩展性,Spring 针对 BeanFactory 做了大量的扩展。

1、BeanFactoryPostProcessor

1)、说明

  • a、BeanFactoryPostProcessor 接口跟 BeanPostProcessor 类似,可以对 bean 的定义(配置元数据)进行处理,即在容器实际实例化任何 bean 之前读取配置元数据,并可能修改它。
  • b、可以配置多个 BeanFactoryPostProcessor,还能通过设置 “order” 来控制 BeanFactoryPostProcessor 的执行顺序(实现 BeanFactoryPostProcessor 接口时,也需要实现 Ordered 接口)。
  • c、如果想改变实际的 bean 实例,最好使用 BeanPostProcessor,它是 bean 级别的,而 BeanFactoryPostProcessor 是容器级别的。

2)、BeanFactoryPostProcessor 的典型应用:PropertyPlaceholderConfigurer

  • 查看 PropertyPlaceholderConfigurer 的继承结构,可看出它间接继承了 BeanFactoryPostProcessor ,它的功能是,当 Spring 加载任何实现 BeanFactoryPostProcessor 接口的 bean 的配置时,都会在 bean 工厂载入所有的 bean 的配置之后执行 postProcessBeanFactory 方法。(目前已经可以用 PropertySourcesPlaceholderConfigurer 来替代,它利用了 PropertySource 和 Environment 的机制,来变得更加灵活)
  • PropertyResourceConfigurer 类中实现了 postProcessBeanFactory 方法,里面先后调用了 mergeProperties(获取配置)、convertProperties(转换为合适的类型)、processProperties(将配置内容告知 BeanFactory)。

示例

app-context-processor.xml


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id="testBean" class="com.luo.spring.guides.post.processor.PostProcessorTestBean">
        <property name="name">
            <value>${bean.name}value>
        property>
    bean>

    <bean id="testBeanHandler" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>postprocessor/bean.propertiesvalue>
            list>
        property>
        <property name="fileEncoding">
            <value>utf-8value>
        property>
    bean>
beans>

bean.properties

bean.name=我是小小罗

PostProcessorTestBean.java

package com.luo.spring.guides.post.processor;

import lombok.Data;

/**
 * @author : archer
 * @date : Created in 2023/1/3 11:36
 * @description :
 */
@Data
public class PostProcessorTestBean {
    private String name;
}

测试

package com.luo.spring.guides.post.processor;

import org.springframework.context.support.GenericXmlApplicationContext;

import java.util.Locale;

/**
 * @author : archer
 * @date : Created in 2023/1/3 11:38
 * @description :
 */
public class Main {
    public static void main(String... args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("classpath:postprocessor/app-context-processor.xml");
        ctx.refresh();

        PostProcessorTestBean testBean = ctx.getBean("testBean", PostProcessorTestBean.class);
        System.out.println(testBean.getName());
        ctx.close();
    }
}

输出

我是小小罗

3)、自定义 BeanFactoryPostProcessor

场景:配置敏感词,展示时忽略

package com.luo.spring.guides.post.processor.custom;

import lombok.Data;
import lombok.ToString;

/**
 * @author : archer
 * @date : Created in 2023/1/9 10:41
 * @description :
 */
@ToString
@Data
public class SimplePostBean {

    private String connectionString;
    private String username;
    private String password;
}
package com.luo.spring.guides.post.processor.custom;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionVisitor;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.util.StringValueResolver;

import java.util.HashSet;
import java.util.Set;

/**
 * @author : archer
 * @date : Created in 2023/1/3 13:06
 * @description :
 */
public class ObscenityRemovingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    private Set<String> obscenities;

    public ObscenityRemovingBeanFactoryPostProcessor() {
        this.obscenities = new HashSet<>();
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String[] beanNames = beanFactory.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
            StringValueResolver valueResolver = new StringValueResolver() {
                @Override
                public String resolveStringValue(String strVal) {
                    if(isObscene(strVal)) return "*****";
                    return strVal;
                }
            };
            BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
            visitor.visitBeanDefinition(bd);
        }
    }

    public boolean isObscene(Object value){
        String potentialObscenity = value.toString().toUpperCase();
        return this.obscenities.contains(potentialObscenity);
    }

    public void setObscenities(Set<String> obscenities){
        this.obscenities.clear();
        for (String obscenity : obscenities) {
            this.obscenities.add(obscenity.toUpperCase());
        }
    }
}

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id="bfpp" class="com.luo.spring.guides.post.processor.custom.ObscenityRemovingBeanFactoryPostProcessor">
        <property name="obscenities">
            <set>
                <value>bollocksvalue>
                <value>winkyvalue>
                <value>bumvalue>
                <value>microsoftvalue>
            set>
        property>
    bean>

    <bean id="simpleBean" class="com.luo.spring.guides.post.processor.custom.SimplePostBean">
        <property name="connectionString">
            <value>bollocksvalue>
        property>
        <property name="username">
            <value>microsoftvalue>
        property>
        <property name="password">
            <value>passwordvalue>
        property>
    bean>

beans>

测试类

package com.luo.spring.guides.post.processor.custom;

import com.luo.spring.guides.post.processor.PostProcessorTestBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

/**
 * @author : archer
 * @date : Created in 2023/1/9 10:51
 * @description :
 */
public class Main {

    public static void main(String... args) {
        ConfigurableListableBeanFactory ctx = new XmlBeanFactory(new ClassPathResource("postprocessor/custom/app-context-processor-custom.xml"));
        BeanFactoryPostProcessor bfpp = (BeanFactoryPostProcessor) ctx.getBean("bfpp");

        bfpp.postProcessBeanFactory(ctx);
        System.out.println( ctx.getBean("simpleBean"));
    }
}

输出

SimplePostBean(connectionString=*****, username=*****, password=password)

4)、BeanFactoryPostProcessor 源码分析

//子类覆盖方法做额外处理:方便业务上做进一步的拓展
this.postProcessBeanFactory(beanFactory); 
//激活各种 BeanFactory 处理器
this.invokeBeanFactoryPostProcessors(beanFactory);
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    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 (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
}

PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors 源码如下

//beanFactoryPostProcessors 硬编码注册的后处理器
public static void invokeBeanFactoryPostProcessors(
    ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    
    // Invoke BeanDefinitionRegistryPostProcessors first, if any.
    Set<String> processedBeans = new HashSet<>();

    //对 BeanDefinitionRegistry 类型的处理
    if (beanFactory instanceof BeanDefinitionRegistry) {
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

        //beanFactoryPostProcessors 硬编码注册的后处理器
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor;
                //对于 BeanDefinitionRegistryPostProcessor 类型,在 BeanFactoryPostProcessor 的基础上还有自己定义的方法,需要先调用
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                registryProcessors.add(registryProcessor);
            }
            else {
                //记录常规的 BeanFactoryPostProcessor
                regularPostProcessors.add(postProcessor);
            }
        }

        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the bean factory post-processors apply to them!
        // Separate between BeanDefinitionRegistryPostProcessors that implement
        // PriorityOrdered, Ordered, and the rest.
        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

        // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
        //首先,调用实现 PriorityOrdered 的 BeanDefinitionRegistryPostProcessors。
        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, beanFactory.getApplicationStartup());
        currentRegistryProcessors.clear();

        // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
        //接下来,调用实现 Ordered 的 BeanDefinitionRegistryPostProcessors。
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }
        //按照优先顺序进行排序
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
        currentRegistryProcessors.clear();

        // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
        //最后,调用所有其他 BeanDefinitionRegistryPostProcessor,直到不再出现为止。
        boolean reiterate = true;
        while (reiterate) {
            reiterate = false;
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                if (!processedBeans.contains(ppName)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                    reiterate = true;
                }
            }
            //按照优先顺序进行排序
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
            currentRegistryProcessors.clear();
        }

        // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
        //现在,调用到目前为止处理的所有处理器的 postProcessBeanFactory 回调。
        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    }

    else {
        //非 BeanDefinitionRegistry 类型的处理,处理的是入参的 beanFactoryPostProcessors,即硬编码注册的后处理器
        // Invoke factory processors registered with the context instance.
        //调用在上下文实例中注册的工厂处理器。
        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }

    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let the bean factory post-processors apply to them!
    String[] postProcessorNames =
        beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

    // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
    // Ordered, and the rest.
     将实现 PriorityOrdered、Ordered 和其他的 BeanFactoryPostProcessors 分开。
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    List<String> orderedPostProcessorNames = new ArrayList<>();
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    for (String ppName : postProcessorNames) {
        if (processedBeans.contains(ppName)) {
            // skip - already processed in first phase above
            //第一阶段已经处理过了
        }
        else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
        }
        else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
            orderedPostProcessorNames.add(ppName);
        }
        else {
            nonOrderedPostProcessorNames.add(ppName);
        }
    }

    // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
    //首先,调用实现 PriorityOrdered 的 BeanFactoryPostProcessors。
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

    // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
    //接下来,调用实现 Ordered 的 BeanFactoryPostProcessors。
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
    for (String postProcessorName : orderedPostProcessorNames) {
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    sortPostProcessors(orderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

    // Finally, invoke all other BeanFactoryPostProcessors.
    //最后,调用所有其他 BeanFactoryPostProcessor。
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
    for (String postProcessorName : nonOrderedPostProcessorNames) {
        nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

    // Clear cached merged bean definitions since the post-processors might have
    // modified the original metadata, e.g. replacing placeholders in values...
     清除缓存的合并 bean 定义,因为后处理器可能已经修改了原始元数据,例如替换值中的占位符...
    beanFactory.clearMetadataCache();
}

对方法进行分解,大致流程分为如下两步:

(1)、对于 BeanDefinitionRegistry 类的特殊处理

  • a、对于硬编码注册的后处理器的处理

    • 主要是通过 AbstractApplicationContext#addBeanFactoryPostProcessor 方法进行添加
  • b、记录后处理器主要使用了2个List完成

    • regularPostProcessors:记录通过硬编码方式配置方式注册的 BeanFactoryPostProcessor 类型的处理器,包含 currentRegistryProcessors
    • registryProcessors:记录通过硬编码方式注册的 BeanDefinitionRegistryPostProcessor 类型的处理器

    补充:**currentRegistryProcessors:**记录通过配置方式注册的 BeanDefinitionRegistryPostProcessor 类型的处理器,对于配置方式注册的,添加后会进行 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 方法调用

  • c、对以上所记录的 List 中的后处理器统一调用 BeanFactoryPostProcessor#postProcessBeanFactory 方法

(2)、对普通的 BeanFactoryPostProcessor 的处理

  • 分成实现 PriorityOrdered、Ordered 和剩下的三种类别的 List
  • 分类之后,调用 BeanFactoryPostProcessor#postProcessBeanFactory 方法

2、注册 BeanPostProcessor

1)、示例:自定义后处理器

package com.luo.spring.guides.common;

/**
 * @author : archer
 * @date : Created in 2023/1/9 15:47
 * @description :
 */
public class TestBean1 {
}
package com.luo.spring.guides.common;

/**
 * @author : archer
 * @date : Created in 2023/1/9 15:47
 * @description :
 */
public class TestBean {
}

package com.luo.spring.guides.post.processor.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;

/**
 * @author : archer
 * @date : Created in 2023/1/9 15:39
 * @description :
 */
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("==========");
        return null;
    }
}

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id="myiabpp" class="com.luo.spring.guides.post.processor.bean.MyInstantiationAwareBeanPostProcessor"/>

    <bean id="testBean" class="com.luo.spring.guides.common.TestBean"/>
    <bean id="testBean1" class="com.luo.spring.guides.common.TestBean1"/>

beans>

测试

package com.luo.spring.guides.post.processor.bean;

import com.luo.spring.guides.common.TestBean;
import org.springframework.context.support.GenericXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2023/1/9 15:42
 * @description :
 */
public class Main {
    public static void main(String[] args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("classpath:postprocessor/bean/bean-processor.xml");
        ctx.refresh();
        ctx.close();
    }
}

输出

==========
==========

可以看到使用 ApplicationContext 容器每初始化一个 bean,都会执行 MyInstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 方法,而使用 BeanFactory 方式进行 bean 初始化,则不会执行方法。

2)、源码解析

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}

PostProcessorRegistrationDelegate#registerBeanPostProcessors 源码如下

public static void registerBeanPostProcessors(
    ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

    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.
    //BeanPostProcessorChecker 是一个普通的信息打印,可能会有些情况,
    //当 Spring 的配置中的后处理器,还没有被注册,就已经开始了 bean 的初始化时,
    //便会打印出 BeanPostProcessorChecker 中设定的信息
    int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
    beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

    // Separate between BeanPostProcessors that implement PriorityOrdered,
    // Ordered, and the rest.
    //使用 PriorityOrdered 保证顺序
    List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
    //使用 Ordered 保证顺序
    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);
        }
    }

    // First, register the BeanPostProcessors that implement PriorityOrdered.
    //首先,注册实现 PriorityOrdered 的 BeanPostProcessors。
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

    // Next, register the BeanPostProcessors that implement Ordered.
    //接下来,注册实现 Ordered 的 BeanPostProcessors
    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.
    //然后,注册所有余下的普通 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.
    //最后,重新注册所有内部的 BeanPostProcessor。
    sortPostProcessors(internalPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, internalPostProcessors);

    // Re-register post-processor for detecting inner beans as ApplicationListeners,
    // moving it to the end of the processor chain (for picking up proxies etc).
    // 将用于检测内部 bean 的后处理器重新注册为 ApplicationListeners,将其移动到处理器链的末尾(用于获取代理等)。
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

因为 BeanPostProcessor 在这里只是进行注册,调用是在 bean 初始化的时候,所以这里就没有硬编码方式的实现了。

3、初始化消息资源

1)、示例:国际化

a、定义资源文件

message.properties

test=test

message_zh_CN.properties

  • 中文会乱码,要转为 ascii 码
  • 工具:https://www.ip138.com/ascii/
//test=测试
test=\u6d4b\u8bd5

message_en_US.properties

test=test

b、定义配置文件



<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/util
         http://www.springframework.org/schema/util/spring-util.xsd">

    
    <bean id="messageSource"
          class="org.springframework.context.support.ResourceBundleMessageSource"
          p:basenames-ref="basenames"/>

    <util:list id="basenames">
        <value>messagevalue>
    util:list>
beans>

c、使用 ApplicationContext 访问国际化信息

package com.luo.spring.guides.messagesource.i18n;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.Properties;

/**
 * @author : archer
 * @date : Created in 2023/1/9 16:25
 * @description :
 */
@Slf4j
public class I18nMain {
    public static void main(String[] args) {
        String[] configs = {"i18n/i18n.xml"};
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(configs);
        String usStr = applicationContext.getMessage("test", null, Locale.US);
        String cnStr = applicationContext.getMessage("test", null, Locale.CHINA);
        System.out.println(cnStr);
        System.out.println(usStr);
    }
}

输出

测试
test

2)、源码分析

/**
 * Initialize the MessageSource.
 * Use parent's if none defined in this context.
 */
protected void initMessageSource() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
        //如果在配置中已经配置了 messageSource,那么将 messageSource 提取并记录在 this.messageSource 中
        this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
        // Make MessageSource aware of parent MessageSource.
        if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
            HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
            if (hms.getParentMessageSource() == null) {
                // Only set parent context as parent MessageSource if no parent MessageSource
                // registered already.
                hms.setParentMessageSource(getInternalParentMessageSource());
            }
        }
        if (logger.isTraceEnabled()) {
            logger.trace("Using MessageSource [" + this.messageSource + "]");
        }
    }
    else {
        // Use empty MessageSource to be able to accept getMessage calls.
        //如果用户没有定义,就使用临时的 DelegatingMessageSource 以便于作为调用 getMessage 方法的返回
        DelegatingMessageSource dms = new DelegatingMessageSource();
        dms.setParentMessageSource(getInternalParentMessageSource());
        this.messageSource = dms;
        beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
        if (logger.isTraceEnabled()) {
            logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
        }
    }
}

4、初始化 ApplicationEventMulticaster

1)、示例

a、定义监听事件

package com.luo.spring.guides.event.multicaster;

import org.springframework.context.ApplicationEvent;

/**
 * @author : archer
 * @date : Created in 2023/1/9 17:59
 * @description :
 */
public class TestEvent extends ApplicationEvent {

    private String msg;


    public TestEvent(Object source, String msg) {
        super(source);
        this.msg = msg;
    }

    public void print() {
        System.out.println("received: " + msg);
    }
}

b、定义监听器

package com.luo.spring.guides.event.multicaster;

import org.springframework.context.ApplicationListener;

/**
 * @author : archer
 * @date : Created in 2023/1/9 18:07
 * @description :
 */
public class TestListener implements ApplicationListener<TestEvent> {

    @Override
    public void onApplicationEvent(TestEvent event) {
        event.print();
    }
}

c、添加配置文件



<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="testListener" class="com.luo.spring.guides.event.multicaster.TestListener"/>
beans>

d、测试

package com.luo.spring.guides.event.multicaster;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2023/1/9 19:43
 * @description :
 */
public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("event/listener.xml");
        ctx.publishEvent(new TestEvent("hello","msg"));
    }
}

输出

received: i am a message

2)、源码解析

/**
 * Initialize the ApplicationEventMulticaster.
 * Uses SimpleApplicationEventMulticaster if none defined in the context.
 * @see org.springframework.context.event.SimpleApplicationEventMulticaster
 */
protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    //若用户定义了事件广播器,则使用用户自定义的
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        if (logger.isTraceEnabled()) {
            logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
        }
    }
    else {
        //若用户没有定义自定义广播器,则使用默认的 SimpleApplicationEventMulticaster
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        if (logger.isTraceEnabled()) {
            logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
                         "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
        }
    }
}

SimpleApplicationEventMulticaster 广播事件的源码如下

@Override
public void multicastEvent(ApplicationEvent event) {
    multicastEvent(event, resolveDefaultEventType(event));
}

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    Executor executor = getTaskExecutor();
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            invokeListener(listener, event);
        }
    }
}

/**
 * Invoke the given listener with the given event.
 * @param listener the ApplicationListener to invoke
 * @param event the current event to propagate
 * @since 4.1
 */
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
    ErrorHandler errorHandler = getErrorHandler();
    if (errorHandler != null) {
        try {
            doInvokeListener(listener, event);
        }
        catch (Throwable err) {
            //异常捕获要执行的方法
            errorHandler.handleError(err);
        }
    }
    else {
        doInvokeListener(listener, event);
    }
}

//调用 ApplicationListener 的 onApplicationEvent 方法
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    try {
        listener.onApplicationEvent(event);
    }
    catch (ClassCastException ex) {
        String msg = ex.getMessage();
        if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
            (event instanceof PayloadApplicationEvent &&
             matchesClassCastMessage(msg, ((PayloadApplicationEvent) event).getPayload().getClass()))) {
            // Possibly a lambda-defined listener which we could not resolve the generic event type for
            // -> let's suppress the exception.
            Log loggerToUse = this.lazyLogger;
            if (loggerToUse == null) {
                loggerToUse = LogFactory.getLog(getClass());
                this.lazyLogger = loggerToUse;
            }
            if (loggerToUse.isTraceEnabled()) {
                loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
            }
        }
        else {
            throw ex;
        }
    }
}

5、注册监听器

两种方式注册监听器

  • 硬编码方式注册的监听器
  • 配置文件注册的监听器
/**
 * Add beans that implement ApplicationListener as listeners.
 * Doesn't affect other listeners, which can be added without being beans.
 */
protected void registerListeners() {
    // Register statically specified listeners first.
    //硬编码方式注册的监听器
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }

    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let post-processors apply to them!
    //配置文件注册的监听器
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // Publish early application events now that we finally have a multicaster...
    //广播器来发布一些早期的应用程序事件,容器启动就发布的事件
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

八、初始化非延迟加载单例

  • 完成 BeanFactory 的初始化工作:包含 ConversionService 的设置、配置冻结以及非延迟加载的 bean 的初始化工作。
/**
	 * Finish the initialization of this context's bean factory,
	 * initializing all remaining singleton beans.
	 */
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // Initialize conversion service for this context.
    //为此上下文初始化转换服务(conversionService)。
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
        beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
            beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }

    // Register a default embedded value resolver if no BeanFactoryPostProcessor
    // (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
    // at this point, primarily for resolution in annotation attribute values.
    //如果没有 BeanFactoryPostProcessor,则注册一个默认的嵌入值解析器
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }

    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    //尽早初始化 LoadTimeWeaverAware bean 以允许尽早注册它们的转换器。
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }

    // Stop using the temporary ClassLoader for type matching.
    //停止使用临时类加载器进行类型匹配。
    beanFactory.setTempClassLoader(null);

    // Allow for caching all bean definition metadata, not expecting further changes.
    //冻结所有的 beanDefinition 的元数据,说明注册的 bean 定义将不被修改或任何进一步的处理
    beanFactory.freezeConfiguration();

    // Instantiate all remaining (non-lazy-init) singletons.
    //初始化剩余的非懒加载的单例
    beanFactory.preInstantiateSingletons();
}

1、设置 ConversionService

之前有使用过自定义类型转换器来把配置文件读取的 String 类型转换为 Date 类型,现在来介绍另一种方式,使用 Conventer。先来看一个简单的示例

1)、示例

a、定义转换器与实例

package com.luo.spring.guides.converter;


import org.springframework.core.convert.converter.Converter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author : archer
 * @date : Created in 2023/1/9 20:21
 * @description :
 */
public class String2DateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String source) {
        SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            return dateFormatter.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }
    }
}
package com.luo.spring.guides.converter;

import lombok.Data;

import java.util.Date;

/**
 * @author : archer
 * @date : Created in 2023/1/9 20:38
 * @description :
 */
@Data
public class DateBean {
    private Date date;
}

b、注册



<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="com.luo.spring.guides.converter.String2DateConverter"/>
            list>
        property>
    bean>
    
    
    <bean id="dateBean" class="com.luo.spring.guides.converter.DateBean">
        <property name="date" value="2023-01-09 20:34:45"/>
    bean>
beans>

c、测试

package com.luo.spring.guides.converter;

import com.luo.spring.guides.event.multicaster.TestEvent;
import lombok.Data;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.convert.support.DefaultConversionService;

import java.util.Date;

/**
 * @author : archer
 * @date : Created in 2023/1/9 20:32
 * @description :
 */
public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("converter/converter.xml");
        DateBean dateBean = (DateBean) ctx.getBean("dateBean");
        System.out.println(dateBean.getDate());
    }
}

输出

Mon Jan 09 20:34:45 CST 2023

2、冻结配置

  • 冻结所有的 beanDefinition 的元数据,说明注册的 bean 定义将不被修改或任何进一步的处理
@Override
public void freezeConfiguration() {
    this.configurationFrozen = true;
    this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
}

3、初始化非延迟加载的单例 bean

  • 默认 ApplicationContext 启动时,将所有非延迟加载的单例 bean 实例化。这样如果配置单例 bean 有问题的话,就可以在启动的时候发现。
@Override
public void preInstantiateSingletons() throws BeansException {
    if (logger.isTraceEnabled()) {
        logger.trace("Pre-instantiating singletons in " + this);
    }

    // Iterate over a copy to allow for init methods which in turn register new bean definitions.
    // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // Trigger initialization of all non-lazy singleton beans...
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {
                    FactoryBean<?> factory = (FactoryBean<?>) bean;
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = AccessController.doPrivileged(
                            (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                            getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                       ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
            }
            else {
                getBean(beanName);
            }
        }
    }

    // Trigger post-initialization callback for all applicable beans...
    for (String beanName : beanNames) {
        Object singletonInstance = getSingleton(beanName);
        if (singletonInstance instanceof SmartInitializingSingleton) {
            StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
                .tag("beanName", beanName);
            SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    smartSingleton.afterSingletonsInstantiated();
                    return null;
                }, getAccessControlContext());
            }
            else {
                smartSingleton.afterSingletonsInstantiated();
            }
            smartInitialize.end();
        }
    }
}

九、finishRefresh

/**
	 * Finish the refresh of this context, invoking the LifecycleProcessor's
	 * onRefresh() method and publishing the
	 * {@link org.springframework.context.event.ContextRefreshedEvent}.
	 */
@SuppressWarnings("deprecation")
protected void finishRefresh() {
    // Clear context-level resource caches (such as ASM metadata from scanning).
    //清除上下文级资源缓存(例如来自扫描的 ASM 元数据)。
    clearResourceCaches();

    // Initialize lifecycle processor for this context.
    //初始化生命周期处理器
    initLifecycleProcessor();

    // Propagate refresh to lifecycle processor first.
    //首先用生命周期处理器来启动所有实现了 Lifecycle 接口的 bean
    getLifecycleProcessor().onRefresh();

    // Publish the final event.
    //发布事件
    publishEvent(new ContextRefreshedEvent(this));

    // Participate in LiveBeansView MBean, if active.
    //参与 LiveBeansView MBean(如果激活)。
    if (!NativeDetector.inNativeImage()) {
        LiveBeansView.registerApplicationContext(this);
    }
}

1、initLifecycleProcessor

  • 当 ApplicationContext 启动或停止时,会通过 LifecycleProcessor 来与所有声明的 bean 周期做状态更新
/**
	 * Initialize the LifecycleProcessor.
	 * Uses DefaultLifecycleProcessor if none defined in the context.
	 * @see org.springframework.context.support.DefaultLifecycleProcessor
	 */
protected void initLifecycleProcessor() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
        this.lifecycleProcessor =
            beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
        if (logger.isTraceEnabled()) {
            logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
        }
    }
    else {
        DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
        defaultProcessor.setBeanFactory(beanFactory);
        this.lifecycleProcessor = defaultProcessor;
        beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
        if (logger.isTraceEnabled()) {
            logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +
                         "[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");
        }
    }
}

2、onRefresh

  • 启动所有实现了 Lifecycle 接口的 bean
@Override
public void onRefresh() {
    startBeans(true);
    this.running = true;
}

private void startBeans(boolean autoStartupOnly) {
    Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
    Map<Integer, LifecycleGroup> phases = new TreeMap<>();

    lifecycleBeans.forEach((beanName, bean) -> {
        if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
            int phase = getPhase(bean);
            phases.computeIfAbsent(
                phase,
                p -> new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly)
            ).add(beanName, bean);
        }
    });
    if (!phases.isEmpty()) {
        phases.values().forEach(LifecycleGroup::start);
    }
}

3、publishEvent

  • 发布 ContextRefreshedEvent (容器加载完成事件)通知事件来做进一步的逻辑处理
@Override
public void publishEvent(ApplicationEvent event) {
    publishEvent(event, null);
}

/**
	 * Publish the given event to all listeners.
	 * @param event the event to publish (may be an {@link ApplicationEvent}
	 * or a payload object to be turned into a {@link PayloadApplicationEvent})
	 * @param eventType the resolved event type, if known
	 * @since 4.2
	 */
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    Assert.notNull(event, "Event must not be null");

    // Decorate event as an ApplicationEvent if necessary
    ApplicationEvent applicationEvent;
    if (event instanceof ApplicationEvent) {
        applicationEvent = (ApplicationEvent) event;
    }
    else {
        applicationEvent = new PayloadApplicationEvent<>(this, event);
        if (eventType == null) {
            eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
        }
    }

    // Multicast right now if possible - or lazily once the multicaster is initialized
    if (this.earlyApplicationEvents != null) {
        this.earlyApplicationEvents.add(applicationEvent);
    }
    else {
        getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    }

    // Publish event via parent context as well...
    if (this.parent != null) {
        if (this.parent instanceof AbstractApplicationContext) {
            ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
        }
        else {
            this.parent.publishEvent(event);
        }
    }
}

你可能感兴趣的:(#,Spring系列,spring,java)