【Spring详解六】容器的功能扩展-ApplicationContext

news/2025/2/26 22:28:58

六、容器的功能扩展_ApplicationContext

经过前几章的分析,对Spring中的容器功能有了简单的了解,在前面几章中一直以 BeanFactory接口以及它的默认实现类XmlBeanFacotory为例进行分析,但是Spring中还提供了 另一个接口ApplicationContext,用于 扩展BeanFactory中现有的功能
ApplicationContext和BeanFactory两者都是 用于加载Bean的,但是相比之下, ApplicationContext提供更多的扩展功能,简单点说,ApplicationContext包含BeanFactory的所有功能。通常建议比BeanFactory优先,除非在一些限制的场合,比如字节长度对内存影响有很大的影响时(Applet)。绝大多数“典型的”企业应用和系统,ApplicationContext就是你需要的。
那么究竟ApplicationContext比BeanFactory多出了哪些功能呢?首先是使用不同类去加载配置文件在写法上的不同,代码如下:
//使用BeanFactory方法加载XML
BeanFactory bf = new XmlBeanFactory(new ClassPathResource(“beanFactoryTest.xml”))
//使用ApplicationContext方法加载XML
ApplicationContext bf = new ClassPathXmlApplicationContext(“beanFactoryTest.xml”);
接下来我们就以ClassPathXmlApplicationContext作为切入点,开始对整体功能进行分析。首先看下其构造函数:
java"># ClassPathXmlApplicationContext
public ClassPathXmlApplicationContext() {
}

public ClassPathXmlApplicationContext(ApplicationContext parent) {
    super(parent);
}

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

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

public ClassPathXmlApplicationContext(String[] configLocations, @Nullable ApplicationContext parent)
        throws BeansException {

    this(configLocations, true, parent);
}

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
    this(configLocations, refresh, null);
}

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
        throws BeansException {
    super(parent);
    setConfigLocations(configLocations);
    if (refresh) {
        refresh();
    }
}
设置路径是必不可少的步骤,ClassPathXmlApplicationContext中可以将配置文件路径以数组的方式传入,ClassPathXmlApplicationContext可以 对数组进行解析并进行加载。而对于解析及功能实现都在 refresh() 中实现。

6.1 设置配置路径——setConfigLocations方法

在ClassPathXmlApplicationContext中支持多个配置文件以数组方式同时传入,以下是设置配置路径 setConfigLocations(configLocations) 方法,代码:
java"># AbstractRefreshableConfigApplicationContext
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] = resolvePath(locations[i]).trim();
        }
    }
    else {
        this.configLocations = null;
    }
}
其中如果给定的路径中包含特殊符号,如${var},那么会在方法 resolvePath() 中解析系统变量并替换。

6.2 扩展功能——refresh方法

设置了路径之后,便可以根据路径做配置文件的解析以及各种功能的实现了。可以说 refresh() 方法中包含了几乎 ApplicationContext 中提供的全部功能,而且此函数中逻辑非常清晰明了,使我们很容易分析对应的层次及逻辑,我们看下方法代码:
java"># AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        //准备刷新的上下文 环境  
        prepareRefresh();
        //初始化BeanFactory,并进行XML文件读取  
        /* 
         * ClassPathXMLApplicationContext包含着BeanFactory所提供的一切特征,在这一步骤中将会复用 
         * BeanFactory中的配置文件读取解析及其他功能,这一步之后,ClassPathXmlApplicationContext 
         * 实际上就已经包含了BeanFactory所提供的功能,也就是可以进行Bean的提取等基础操作了。 
         */  
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        //对beanFactory进行各种功能填充  
        prepareBeanFactory(beanFactory);
        try {
            //子类覆盖方法做额外处理  
            /* 
             * Spring之所以强大,为世人所推崇,除了它功能上为大家提供了便利外,还有一方面是它的 
             * 完美架构,开放式的架构让使用它的程序员很容易根据业务需要扩展已经存在的功能。这种开放式 
             * 的设计在Spring中随处可见,例如在本例中就提供了一个空的函数实现postProcessBeanFactory来 
             * 方便程序猿在业务上做进一步扩展 
             */ 
            postProcessBeanFactory(beanFactory);
            //激活各种beanFactory后处理器  
            invokeBeanFactoryPostProcessors(beanFactory);
            //注册拦截Bean创建的Bean后处理器,这里只是注册,真正的调用实在getBean时候 
            registerBeanPostProcessors(beanFactory);
            //为上下文初始化Message源,即不同语言的消息体,国际化处理  
            initMessageSource();
            //初始化应用消息广播器,并放入“applicationEventMulticaster”bean中  
            initApplicationEventMulticaster();
            //留给子类来初始化其它的Bean  
            onRefresh();
            //在所有注册的bean中查找Listener bean,注册到消息广播器中  
            registerListeners();
            //初始化剩下的单实例(非惰性的)  
            finishBeanFactoryInitialization(beanFactory);
            //完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人  
            finishRefresh();
        }
        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                        "cancelling refresh attempt: " + ex);
            }
            destroyBeans();
            cancelRefresh(ex);
            throw ex;
        }
        finally {
            resetCommonCaches();
        }
    }
}
我们简单的分析下代码的步骤:
  1. prepareRefresh()——初始化前的准备工作,例如对系统属性或者环境变量进行准备及验证 。在某种情况下项目的使用需要读取某些系统变量,而这个变量的设置很可能会影响着系统的正确性,那么 ClassPathXmlApplicationContext 为我们提供的这个准备方法就显得非常必要,他可以在spring启动的时候提前对必须的环境变量进行存在性验证。
  2. obtainFreshBeanFactory()——初始化BeanFactory,并进行XML文件读取。之前提到 ClassPathXmlApplicationContext 包含着对 BeanFactory 所提供的一切特征,那么这一步中将会复用BeanFactory中的配置文件读取解析其他功能,这一步之后ClassPathXmlApplicationContext实际上就已经包含了BeanFactory所提供的功能,也就是可以进行Bean的提取等基本操作了。
  3. prepareBeanFactory(beanFactory)——对BeanFactory进行各种功能填充。@Qualifier@Autowired应该是大家非常熟悉的注解了,那么这两个注解正是在这一步骤中增加支持的。
  4. postProcessBeanFactory(beanFactory)——子类覆盖方法做额外处理。spring之所以强大,为世人所推崇,除了它功能上为大家提供了遍历外,还有一方面是它完美的架构,开放式的架构让使用它的程序员很容易根据业务需要扩展已经存在的功能。这种开放式的设计在spring中随处可见,例如本类中就提供了一个空的函数实现 postProcessBeanFactory() 来方便程序员在业务上做进一步的扩展。
  5. invokeBeanFactoryPostProcessors(beanFactory)——激活各种BeanFactory后处理器。
  6. registerBeanPostProcessors(beanFactory)——注册拦截bean创建的bean后处理器,这里只是注册,真正的调用是在getBean时候。
  7. initMessageSource()——为上下文初始化Message源,及对不同语言的小西天进行国际化处理。
  8. initApplicationEventMulticaster()——初始化应用消息广播器,并放入“applicationEventMulticaster”bean中。
  9. onRefresh()——留给子类来初始化其他的bean。
  10. registerListeners()——在所有注册的bean中查找listener bean,注册到消息广播器中。
  11. finishBeanFactoryInitialization(beanFactory)——初始化剩下的单实例(非惰性的)。
  12. finishRefresh()——完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人。
接下来我们就详细的讲解每一个过程。

6.3 prepareRefresh()——刷新上下文的准备工作

AbstractApplicationContext.class
prepareRefresh() 主要是做准备工作,例如对系统属性及环境变量的初始化及验证。代码如下:
java"># AbstractApplicationContext
/**
 * 准备刷新上下文环境,设置它的启动日期和活动标志,以及执行任何属性源的初始化。
 * Prepare this context for refreshing, setting its startup date and
 * active flag as well as performing any initialization of property sources.
 */
protected void prepareRefresh() {
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);

    // 在上下文环境中初始化任何占位符属性源。(空的方法,留给子类覆盖)
    initPropertySources();

    // 验证需要的属性文件是否都已放入环境中
    getEnvironment().validateRequiredProperties();

    // 允许收集早期的应用程序事件,一旦有了多播器,就可以发布……
    this.earlyApplicationEvents = new LinkedHashSet<>();
}
举例如下图:

6.4 obtainFreshBeanFactory()——读取xml并初始化BeanFactory

AbstractApplicationContext.class

obtainFreshBeanFactory() 方法从字面理解是获取beanFactory。ApplicationContext是对BeanFactory的扩展,在其基础上添加了大量的基础应用,obtainFreshBeanFactory() 正式实现beanFactory的地方,经过这个方法后ApplicationContext就有了BeanFactory的全部功能。
我们看下此方法的代码:
java">protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    //初始化BeanFactory,并进行XML文件读取,并将得到的BeanFactory记录在当前实体的属性中  
    refreshBeanFactory();
    //返回当前实体的beanFactory属性 
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}
继续深入到 refreshBeanFactory() 方法中,方法的实现是在 AbstractRefreshableApplicationContext 中:
java"># AbstractRefreshableApplicationContext
@Override
protected final void refreshBeanFactory() throws BeansException {
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    try {
        //创建DefaultListableBeanFactory  
        /* 
         * 以前我们分析BeanFactory的时候,不知道是否还有印象,声明方式为:BeanFactory bf =  
         * new XmlBeanFactory("beanFactoryTest.xml"),其中的XmlBeanFactory继承自DefaulltListableBeanFactory; 
         * 并提供了XmlBeanDefinitionReader类型的reader属性,也就是说DefaultListableBeanFactory是容器的基础。必须 
         * 首先要实例化。 
         */  
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        //为了指定序列化id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象  
        beanFactory.setSerializationId(getId());
        //定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖以及设置  
        //@Autowired和Qualifier注解解析器QualifierAnnotationAutowireCandidateResolver  
        customizeBeanFactory(beanFactory);
        //加载BeanDefiniton  
        loadBeanDefinitions(beanFactory);
        synchronized (this.beanFactoryMonitor) {
            //使用全局变量记录BeanFactory实例。  
            //因为DefaultListableBeanFactory类型的变量beanFactory是函数内部的局部变量,  
            //所以要使用全局变量记录解析结果  
            this.beanFactory = beanFactory;
        }
    }
    catch (IOException ex) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}
我们详细分析上面每个步骤:
  1. createBeanFactory()——创建DefaultListableBeanFactory 。
  2. beanFactory.setSerializationId(getId())——指定序列化id 。
  3. customizeBeanFactory(beanFactory)——定制beanFactory,设置相关属性 。
  4. loadBeanDefinitions(beanFactory)——加载BeanDefiniton 。
  5. this.beanFactory = beanFactory——使用全局变量记录BeanFactory实例

6.4.1 customizeBeanFactory(beanFactory)——定制beanFactory

这里已经开始了对 BeanFactory 的扩展,在基本容器的基础上,增加了是否允许覆盖、是否允许扩展的设置,并提供了解析注解 @Qualifier 和 @Autowire的支持。
java">protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
    //如果属性allowBeanDefinitionOverriding不为空,设置beanFactory相应属性
    //此属性的含义:是否允许覆盖同名称的不同定义的对象
   if (this.allowBeanDefinitionOverriding != null) {
      beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
   }
   //如果属性allowCircularReferences不为空,设置beanFactory相应属性
   //此属性含义:是否允许bean之间存在循环依赖
   if (this.allowCircularReferences != null) {
      beanFactory.setAllowCircularReferences(this.allowCircularReferences);
   }
   beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver())
}
对于允许覆盖和允许依赖的设置这里只是判断了是否为空,如果不为空要进行设置,但是并没有看到在哪里设置。还是那句话,使用子类覆盖:
java">public MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
    //......
    protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
        super.setAllowBeanDefinitionOverriding(false);
        super.setAllowCircularReferences(false);
        super.customizeBeanFactory(beanFactory);
    }
}
对于定制 beanfactory ,Spring 还提供了另外一个重要的扩展,就是设置 AutowireCandidateResolver ,在bean加载部分中讲解创建bean时,采用了 autowireByType 方式注入,那么会默认使用 Spring 提供的 SimpleAutowireCandidateResolver ,而对于默认的实现并没有过多的逻辑处理。在这里,Spring 使用了 QualifierAnnotationAutowireCandidateResolver ,设置了这个解析器后 Spring 就可以支持注解方式的注入了 。
在讲解 autowireByType 根据类型自动注入时,我们说过解析 autowire 类型时首先会调用:
java">Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
因此我们知道,在 QualifierAnnotationAutowireCandidateResolver 中一定会提供解析注解 @Qualifier 和 @Autowire的方法:
java">public Object getSuggestedValue(DependencyDescriptor descriptor) {
   Object value = findValue(descriptor.getAnnotations());
   if (value == null) {
      MethodParameter methodParam = descriptor.getMethodParameter();
      if (methodParam != null) {
         value = findValue(methodParam.getMethodAnnotations());
      }
   }
   return value;
}

6.4.2 loadBeanDefinitions(beanFactory)——加载BeanDefiniton

在第一步中提到了将 ClassPathXmlApplicationContext 与 XMLBeanFactory 创建的对比,除了初始化DefaultListableBeanFactory外,还需要XmlBeanDefinitionReader 来读取XML,那么在 loadBeanDefinitions(beanFactory) 方法中首先要做的就是初始化 XmlBeanDefinitonReader,我们跟着到loadBeanDefinitions(beanFactory)方法体中,我们看到的是在 AbstractXmlApplicationContext中实现的,具体代码如下:
java"># AbstractXmlApplicationContext
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // Create a new XmlBeanDefinitionReader for the given BeanFactory.
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    // Configure the bean definition reader with this context's
    // resource loading environment.
    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.
    initBeanDefinitionReader(beanDefinitionReader);
    loadBeanDefinitions(beanDefinitionReader);
}
在初始化了 DefaultListableBeanFactoryXmlBeanDefinitionReader 后,就可以进行配置文件的读取了。继续进入到 loadBeanDefinitions(beanDefinitionReader)方法体中,代码如下:
java"># AbstractXmlApplicationContext
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 中已经将之前初始化的 DefaultListableBeanFactory 注册进去了,所以XmlBeanDefinitionReader所读取的 BeanDefinitionHolder 都会注册到 DefinitionListableBeanFactory 中,也就是经过这个步骤,DefaultListableBeanFactory 的变量 beanFactory 已经包含了所有解析好的配置。

6.5 prepareBeanFactory(beanFactory)——对BeanFactory进行各种功能填充

AbstractApplicationContext.class
prepareBeanFactory(beanFactory) 就是在功能上扩展的方法,而在进入这个方法前spring已经完成了对配置的解析,接下来我们详细分析下次函数,进入方法体:
java"># AbstractApplicationContext
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());
    //设置beanFactory的表达式语言处理器,Spring3增加了表达式语言的支持,  
    //默认可以使用#{bean.xxx}的形式来调用相关属性值  
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    //为beanFactory增加了一个的propertyEditor,这个主要是对bean的属性等设置管理的一个工具
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // Configure the bean factory with context callbacks.
    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 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.
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // Detect a LoadTimeWeaver and prepare for weaving, if found.
    //增加对AspectJ的支持 
    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()));
    }

    // 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());
    }
}
详细分析下代码发现上面函数主要是在以下方法进行了扩展:
(1)对SPEL语言的支持
(2)增加对属性编辑器的支持
(3)增加对一些内置类的支持,如EnvironmentAware、MessageSourceAware的注入
(4)设置了依赖功能可忽略的接口
(5)注册一些固定依赖的属性
(6)增加了AspectJ的支持
(7)将相关环境变量及属性以单例模式注册

6.5.1 对SPEL语言的支持

AbstractApplicationContext.class
Spring表达式语言全称为“ Spring Expression Language”,缩写为“SpEL”,类似于Struts 2x中使用的OGNL语言,SpEL是单独模块,只依赖于core模块,不依赖于其他模块,可以单独使用。
SpEL使用 #{…} 作为定界符,所有在大框号中的字符都将被认为是SpEL,使用格式如下:
java"><util:properties id="database" location="classpath:db.properties">  
</util:properties>  
<bean id="dbcp" class="org.apache.commons.dbcp.BasicDataSource">  
  <property name="username" value="#{database.user}"></property>  
  <property name="password" value="#{database.pwd}"></property>  
  <property name="driverClassName" value="#{database.driver}"></property>  
  <property name="url" value="#{database.url}"></property>  
</bean>
上面只是列举了其中最简单的使用方式,SpEL功能非常强大,使用好可以大大提高开发效率。
在源码中通过代码 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver()) 方法注册语言解析器,就可以对SpEL进行解析了,那么之后是在什么地方调用这个解析器的呢?
之前我们讲解 beanFactory 中说过 Spring 在bean进行初始化的时候会有属性填充的一步,而在这一步中 Spring 会调用 AbstractAutowireCapabelBeanFactory 类的 applyPropertyValues() 来进行属性值得解析。同时这个步骤中一般通过 AbstractBeanFactory 中的 evaluateBeanDefinitionString() 方法进行SpEL解析,方法代码如下:
java"># AbstractBeanFactory
protected Object evaluateBeanDefinitionString(String value, BeanDefinition beanDefinition) {  
    if (this.beanExpressionResolver == null) {  
        return value;  
    }  
    Scope scope = (beanDefinition != null ? getRegisteredScope(beanDefinition.getScope()) : null);  
    return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));  
}

6.5.2 增加属性注册编辑器

AbstractApplicationContext.class
在 Spring DI 注入时可以把普通属性注入进来,但是像Date类型就无法被识别。例如:
java">public class UserManager {
    private Date dateValue;
    //... get/set
    public String toString(){
        return "dateValue: " + dateValue;
    }
}

//bean.xml  对日期属性进行注入
<bean id="userManager" class="com.test.UserManager">
    <property name="dateValue">
        <value>2022-11-03</value>
   </property>
</bean>

//测试代码
@Test
public void testDate () {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml")
    UserManager userManager = (UserManager)ctx.getBean("userManager");
    System.out.println(userManager);
}
如果直接这样使用,程序会报异常,类型转换不成功。因为在 UserManager 中 dateValue 属性是 Date 类型的,而在XML中配置的却是 String 类型的,所以当然会报异常。
Spring 对此提供了两种解决办法。
(1)使用自定义属性编辑器。
继承 PropertyEditorSupport ,重写 setAsText() 方法,具体如下:
java">// 1.编写自定义属性编辑器
public class DatePropertyEditor extends PropertyEditorSupport {
    private String format = "yyyy-MM-dd";
    public void setFormat (String format) {
        this.format = format;
    }
    public void setAsText (String arg0) throws IllegalArgumentException {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            Date date = sdf.parse(arg0);
            this.setValue(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

// 2.将自定义属性编辑器注册到Spring中
<!-- 自定义属性编辑器 -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="customEditors">
        <map>
            <entry key="java.util.Date">
                <bean class="com.test.DatePropertyEditor">
                    <property name="format" value="yyyy-MM-dd" />
                </bean>
            </entry>
        </map>
   </property>
</bean>
在配置文件中引入 org.springframework.beans.factory.config. CustomEditorConfigurer 的bean,并在属性 customEditors 中加入自定义属性编辑器,其中 key 为属性编辑器所对应的类型。通过这样的配置,当 Spring 在注入bean的属性时一旦遇到了 java.util.Date 类型的属性会自动调用自定义的 DatePropertyEditor 解析器进行解析,并用解析结果代替配置属性值进行注入。
(2)注册 Spring 自带的属性编辑器 CustomDateEditor
java">// 1.自定义属性编辑器
public class DatePropertyEditorRegistrar implements PropertyEditorRegistrar {
    public void registerCustomEditors(PropertyEditorRegistry registry) {
        registry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true))
    }
}

// 2.注册到Spring中
<!-- 注册 Spring 自带的属性编辑器 -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="propertyEditorRegistrars">
        <list>
            <bean class="com.test.DatePropertyEditorRegistrar"></bean>
        </list>
   </property>
</bean>
通过在配置文件中将自定义的 DatePropertyEditorRegistrar 注册进入 org.springframework.beans.factory.config.CustomEditorConfigurer 的 propertyEditorRegistrars 属性中,可以实现同方法(1)中同样的效果。
我们回到 Spring 增加属性注册编辑器的代码:
java"># AbstractApplicationContext
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
因为注册 Spring 自定义属性编辑器实现的是 PropertyEditorRegistrarregisterCustomEditors(PropertyEditorRegistry registry) 方法,所以我们来看 ResourceEditorRegistrar 类的 registerCustomEditors() 方法,代码如下:
java"># ResourceEditorRegistrar
@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));
   }
}

private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
   if (registry instanceof PropertyEditorRegistrySupport) {
      ((PropertyEditorRegistrySupport) registry).overrideDefaultEditor(requiredType, editor);
   }
   else {
      registry.registerCustomEditor(requiredType, editor);
   }
}
结合之前注册 Spring 自带的属性编辑器的内容来看,我们发现核心代码 registry.registerCustomEditor(requiredType, editor) ,发现Spring 增加属性注册编辑器这个步骤无非是 注册了一系列常用类型的属性编辑器
那么,我们是在哪里调用 ResourceEditorRegistrar #registerCustomEditors() 进行注册的呢,我们来查看其调用层次结构:
我们看到,就是 AbstractBeanFactory #initBeanWrapper() 方法,这是在 bean 初始化时使用的一个方法,之前已经讲过了。主要是在将 BeanDefinition 转换为 BeanWrapper 后用于对属性的填充。到此,逻辑已经明了,在 bean 初始化后会调用 ResourceEditorRegistrar #registerCustomEditors() 方法进行批量地通用属性编辑器注册。注册后,在属性填充环节便可以直接让 Spring 使用这些编辑器进行属性的解析了。
既然提到了 BeanWrapper ,这里也有必要强调下,Spring 中用于封装 bean 的是 BeanWrapper 类型,而它又间接继承了 PropertyEditorRegistrar 类型,也就是我们之前反复看到的方法参数 PropertyEditorRegistry registry 大部分时候都是 BeanWrapper,对于 BeanWrapper 在 Spring 中的默认实现是 BeanWrapperImpl ,而 BeanWrapperImpl 除了实现 BeanWrapper 接口,还继承了 PropertyEditorRegistrySupport ,在 PropertyEditorRegistrySupport 中有这样一个方法:
java">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);
   }
}

6.5.3 添加 ApplicationContextAwareProcessor 处理器

AbstractApplicationContext.class
增加对一些内置类的支持,如 EnvironmentAwareMessageSourceAware的注入。
我们来看 ApplicationContextAwareProcessor ,它实现了 BeanPostProcessor 接口。我们回顾一下之前讲的内容,在 bean 实例化时,也就是 Spring激活 init-method 的前后,会调用 BeanPostProcessorpostProcessBeforeInstantiation() 方法和 postProcessAfterInitialization() 方法。同样,对于 ApplicationContextAwareProcessor ,我们也关心这两个方法。
对于 ApplicationContextAwareProcessor #postProcessAfterInitialization() 方法,其中并没有做过多逻辑处理。
我们重点来看 ApplicationContextAwareProcessor #postProcessBeforeInstantiation() 方法 :
java"># ApplicationContextAwareProcessor
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;
   }

   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);
   }
}
invokeAwareInterfaces() 方法中,我们可以看出,实现这些 Aware 接口的 bean 在被初始化之后,可以取得一些相应的资源。

6.5.4 设置忽略依赖

AbstractApplicationContext.class
当 Spring 将 ApplicationContextAwareProcessor 注册后,那么在 invokeAwareInterfaces() 方法中间调用的 Aware 已经不是普通的 bean 了,如 ResourceLoaderAwareApplicationEventPublisherAware 等,那么当然需要在 Spring 做 bean 的依赖注入时忽略它们, ignoreDependencyInterface() 方法的作用正在于此。

6.5.5 注册依赖

AbstractApplicationContext.class
当注册了依赖解析后,例如当注册了对 BeanFactory.class 的依赖解析后,当 bean 的属性注入时,一担检测到属性为 BeanFactory 类型便会将 beanFactory 的实例注入进去。

6.6 invokeBeanFactoryPostProcessors(beanFactory)——BeanFactory的后处理

BeanFactory 作为Spring中容器功能的基础,用于存放所有已经加载的bean,为了保证程序上的高可扩展性,Spring针对 BeanFactory 做了大量的扩展,比如我们熟悉的 PostProcessor 就是在这里实现的。接下来我们就深入分析下 BeanFactory 后处理。

6.6.1 激活注册的BeanFactoryPostProcessor

AbstractApplicationContext.class
在正式介绍 BeanFactoryPostProcessor 的后处理前我们先简单的了解下其用法。
BeanFactoryPostProcessor 接口跟 BeanPostProcessor 类似,都可以对bean的定义(配置元数据)进行处理,也就是说spring IoC容器允许 BeanFactoryPostProcessor 在容器实际实例化任何其他的bean之前读取配置元数据,并可能修改他。也可以配置多个 BeanFactoryPostProcessor ,可以通过 order属性来控制 BeanFactoryPostProcessor 的执行顺序(此属性必须当 BeanFactoryPostProcessor 实现了 Ordered 的接口时才可以设置,因此在实现 BeanFactoryPostProcessor 时应该考虑实现 Ordered 接口)。
如果想改变实际的bean实例(例如从配置元数据创建的对象),那最好使用 BeanPostProcessor 。同样的 BeanFactoryPostProcessor的作用域范围是容器级别的,它只是和你所使用的容器有关。如果你在容器中定义了一个 BeanFactoryPostProcessor,它仅仅对此容器中的bean进行后置处理。BeanFactoryPostProcessor 不会对定义在另一个容器中的bean进行后置处理,即使这两个容器都在同一层次上。在spring中存在对于BeanFactoryPostProcessor 的典型应用,如 PropertyPlaceholderConfigurer
(1)BeanFactoryPostProcessor的典型应用:PropertyPlaceholderConfigurer
有时候我们在阅读spring的配置文件中的Bean的描述时,会遇到类似如下情况:
java">public class User {
    private String name;
    private String birthday;
    //... get/set
}
<bean id="user" class="com.yhl.myspring.demo.applicationcontext.User">
    <property name="name" value="${user.name}"/>
    <property name="birthday" value="${user.birthday}"/>
</bean>
这其中出现了变量引用:${user.name}、{user.birthday},这是spring的分散配置,可以在另外的配置文件中为user.name、user.birthday指定值,例如在 bean.properties 文件中定义:
java">user.name = xiaoming
user.birthday = 2019-04-19
当访问名为 user 的bean时,其name属性就会被字符串 xiaoming 替换,那spring框架是怎么知道存在这样的配置文件呢,这个就是 PropertyPlaceholderConfigurer,需要在配置文件中添加一下代码:
java"><bean id="userHandler" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath:bean.properties</value>
        </list>
    </property>
</bean>
在这个bean中指定了配置文件的位置。其实还是有个问题,这个 userHandler 只不过是spring框架管理的一个bean,并没有被别的bean或者对象引用,spring的 beanFactory 是怎么知道这个需要从这个bean中获取配置信息呢?
我们看下PropertyPlaceholderConfigurer这个类的层次结构,如下图:
从上图中我们可以看到 PropertyPlaceholderConfigurer 间接的继承了 BeanFactoryPostProcessor 接口,这是一个很特别的接口,当spring加载任何 实现了这个接口的bean的配置时,都会在 bean工厂载入所有bean的配置之后执行 postProcessBeanFactory() 方法。在 PropertyResourceConfigurer类中实现了 postProcessBeanFactory() 方法,在方法中先后调用了 mergeProperties() convertProperties()processProperties() 这三个方法,分别 得到配置,将 得到的配置转换为合适的类型,最后 将配置内容告知 BeanFactory
正是 通过实现BeanFactoryPostProcessor接口,BeanFactory会在实例化任何bean之前获得配置信息,从而能够正确的解析bean描述文件中的变量引用。
java"># PropertyResourceConfigurer
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    try {
        Properties mergedProps = this.mergeProperties();
        this.convertProperties(mergedProps);
        this.processProperties(beanFactory, mergedProps);
    } catch (IOException var3) {
        throw new BeanInitializationException("Could not load properties", var3);
    }
}
(2)自定义BeanFactoryPostProcessor
编写实现了 BeanFactoryPostProcessor 接口的 MyBeanFactoryPostProcessor 的容器后处理器,如下代码:
java">public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    private Set<String> obscenties;
    public MyBeanFactoryPostProcessor(){
        this.obscenties = new HashSet<>();
    }
    //obscenties包含,则返回***
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String[] beanNames = beanFactory.getBeanDefinitionNames();
        for(String beanName : beanNames) {
            BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
            StringValueResolver valueResolver = new StringValueResolver () {
                public String resolveStringValue (String strVal) {
                    if (this.obscenties.contains(strVal)) {
                        return "***";
                    }
                    return strVal;
                }
            };
        }
    }
}
然后在配置文件中注册这个bean,如下:
java">public class User {
    private String name;
    private String birthday;
    //... get/set/toString
}

//配置文件 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.Springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="www.Springframework.org/schema/beans http://www.Springframework.org/schema/beans/Spring-beans.xsd">
<bean id="myPost" class="com.yhl.myspring.demo.applicationcontext.MyBeanFactoryPostProcessor">
    <property name="obscenties">
        <set>
            <value>wangjiafu</value>
            <value>aaa</value>
        </set>
    </property>
</bean>

<bean id="user" class="com.yhl.myspring.demo.applicationcontext.User">
    <property name="name" value="wangjiafu"/>
    <property name="birthday" value="2019-04-19"/>
</bean>
最后编写测试代码:
java">public class Test {
    public static void main(String[] args) {
        ConfigurableListableBeanFactory bf = (ConfigurableListableBeanFactory) new ClassPathXmlApplicationContext("applicationContext.xml");
        MyBeanFactoryPostProcessor myPost = (MyBeanFactoryPostProcessor)bf.getBean("myPost");
        myPost.postProcessBeanFactory(bf);
        User user = (User)bf.getBean("user");
        System.out.println(user.getName());
    }
}
//结果打印
User{name=***,birthday=2019-04-19}
通过 MyBeanFactoryPostProcessor ,我们很好的屏蔽掉了 obscenties 定义的不该展示的属性。
(3) invokeBeanFactoryPostProcessors(beanFactory) ——激活BeanFactoryPostProcessor
在了解 BeanFactoryPostProcessor 的用法后我们便可以深入的研究 BeanFactoryPostProcessor 的调用过程了,其是在 AbstractApplicationContext #refresh() 方法中的 invokeBeanFactoryPostProcessors(beanFactory) 中实现的,进入到方法内部:
java"># AbstractApplicationContext
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
   PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

   if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }
}
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
   return this.beanFactoryPostProcessors;
}

# PostProcessorRegistrationDelegate
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

    // 1、如果是BeanDefinitionRegistry的实例,首先调用BeanDefinitionRegistryPostProcessors
    Set<String> processedBeans = new HashSet<>();

    // beanFactory是BeanDefinitionRegistry类型
    if (beanFactory instanceof BeanDefinitionRegistry) {
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        // 定义BeanFactoryPostProcessor集合
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
        // 定义BeanDefinitionRegistryPostProcessor集合
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

        // 循环手动注册的beanFactoryPostProcessors
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            // 如果是BeanDefinitionRegistryPostProcessor的实例话,则调用其postProcessBeanDefinitionRegistry方法,对bean进行注册操作
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                // 如果是BeanDefinitionRegistryPostProcessor类型,则直接调用其postProcessBeanDefinitionRegistry
                BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor;
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                registryProcessors.add(registryProcessor);
            }
            // 否则则将其当做普通的BeanFactoryPostProcessor处理,直接加入regularPostProcessors集合,以备后续处理
            else {
                regularPostProcessors.add(postProcessor);
            }
        }

        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

        // 首先调用实现了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集合
        registryProcessors.addAll(currentRegistryProcessors);
        // 调用所有实现了PriorityOrdered的的BeanDefinitionRegistryPostProcessors的postProcessBeanDefinitionRegistry方法,注册bean
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        // 清空currentRegistryProcessors,以备下次使用
        currentRegistryProcessors.clear();

        // 其次,调用实现了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集合
        registryProcessors.addAll(currentRegistryProcessors);
        // 调用所有实现了PriorityOrdered的的BeanDefinitionRegistryPostProcessors的postProcessBeanDefinitionRegistry方法,注册bean
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        // 清空currentRegistryProcessors,以备下次使用
        currentRegistryProcessors.clear();

        // 最后,调用其他的BeanDefinitionRegistryPostProcessors
        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集合
            registryProcessors.addAll(currentRegistryProcessors);
            // 调用其他的BeanDefinitionRegistryPostProcessors的postProcessBeanDefinitionRegistry方法,注册bean
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            // 清空currentRegistryProcessors,以备下次使用
            currentRegistryProcessors.clear();
        }

        // 调用所有BeanDefinitionRegistryPostProcessor(包括手动注册和通过配置文件注册)
        // 和BeanFactoryPostProcessor(只有手动注册)的回调函数-->postProcessBeanFactory
        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    }

    // 2、如果不是BeanDefinitionRegistry的实例,那么直接调用其回调函数即可-->postProcessBeanFactory
    else {
        // Invoke factory processors registered with the context instance.
        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }

    // 3、上面的代码已经处理完了所有的BeanDefinitionRegistryPostProcessors和手动注册的BeanFactoryPostProcessor
    // 接下来要处理通过配置文件注册的BeanFactoryPostProcessor
    // 首先获取所有的BeanFactoryPostProcessor(注意:这里获取的集合会包含BeanDefinitionRegistryPostProcessors)
    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

    // 这里,将实现了PriorityOrdered,Ordered的处理器和其他的处理器区分开来,分别进行处理
    // PriorityOrdered有序处理器
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    // Ordered有序处理器
    List<String> orderedPostProcessorNames = new ArrayList<>();
    // 无序处理器
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    for (String ppName : postProcessorNames) {
        // 判断processedBeans是否包含当前处理器(processedBeans中的处理器已经被处理过);如果包含,则不做任何处理
        if (processedBeans.contains(ppName)) {
            // skip - already processed in first phase above
        }
        else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            // 加入到PriorityOrdered有序处理器集合
            priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
        }
        else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
            // 加入到Ordered有序处理器集合
            orderedPostProcessorNames.add(ppName);
        }
        else {
            // 加入到无序处理器集合
            nonOrderedPostProcessorNames.add(ppName);
        }
    }

    // 首先调用实现了PriorityOrdered接口的处理器
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

    // 其次,调用实现了Ordered接口的处理器
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
    for (String postProcessorName : orderedPostProcessorNames) {
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    sortPostProcessors(orderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

    // 最后,调用无序处理器
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
    for (String postProcessorName : nonOrderedPostProcessorNames) {
        nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

    // 清理元数据
    beanFactory.clearMetadataCache();
}
我们跟进 invokeBeanFactoryPostProcessors() 方法,方法内循环遍历 BeanFactoryPostProcessor 中的 postProcessBeanFactory() 方法 :
java"># PostProcessorRegistrationDelegate
private static void invokeBeanFactoryPostProcessors(
        Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {

    for (BeanFactoryPostProcessor postProcessor : postProcessors) {
        postProcessor.postProcessBeanFactory(beanFactory);
    }
}
invokeBeanFactoryPostProcessors() 方法源码我们看到,对于 BeanFactoryPostProcessor 的处理主要分两种情况进行,一个是对于 BeanDefinitionRegistry 类的特殊处理,另一种是对普通 BeanFactoryPostProcessor 进行处理。而对于两种情况都需要考虑硬编码注入注册的后处理器以及通过配置注入的后处理器。
对于 BeanDefinitionRegistry 类型的特殊处理主要包括以下内容:
  1. 对于硬编码注册的后处理器 PostProcessor 的处理。主要通过 AbstractApplicationContext#addBeanFactoryPostProcessor() 添加处理器方法添加。
  1. 记录后处理器主要使用了3个List完成。
    1. registryPostProcessors() :记录通过硬编码方式注册的 BeanDefinitionRegistryPostProcessor 类型的处理器。
    2. regularPostProcessors() :记录通过硬编码方式注册的 BeanFactoryPostProcessor 类型的处理器。
    3. registryPostProcessorBeans() :记录通过配置方式注册的 BeanDefinitionRegistryPostProcessor 类型的处理器。
  2. 对于以上记录在 List 中的后处理器进行统一调用 BeanFactoryPostProcessor#postProcessBeanFactory() 方法。
    1. ConfigurationClassPostProcessor :实现了 BeanDefinitionRegistryPostProcessor ,遍历记录在 List 中的后处理器进行统一调用 BeanFactoryPostProcessor#postProcessBeanFactory() 方法时,会进入ConfigurationClassPostProcessor#postProcessBeanFactory() 方法,通过 ConfigurationClassParser#parse() 方法解析 configClasses,然后调用 this.reader.loadBeanDefinitions(configClasses) 加载为BeanDefinition。Springboot就是在这一步定位(ComponentScan注解)并扫描需要加载的类,注册到beanDefinitionMap中。【自动装配】
  3. 对于 beanFactoryPostProcessors非 BeanDefinitionRegistryPostProcessor 类型的后处理器进行统一调用 BeanFactoryPostProcessor#postProcessBeanFactory() 方法。
  4. 普通 beanFactory 处理 。

6.6.2 注册BeanPostProcessor

AbstractApplicationContext.class
在上文中提到了 BeanFactoryPostProcessor 的调用,接下来我们就探索下 BeanPostProcessor 。但这里并不是调用,而是注册, 真正的调用其实是在bean的实例化阶段进行的,这是一个很重要的步骤,也是很多功能 BeanFactory 不知道的重要原因。 spring中大部分功能都是通过后处理器的方式进行扩展的,这是spring框架的一个特写,但是 BeanFactory 中其实并没有实现后处理器的自动注册,所以在调用的时候如果没有进行手动注册其实是不能使用的。但是 ApplicationContext 中却添加了自动注册功能,如自定义一个后处理器:
java">public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("befor");
        return null;
    }
}

//配置文件 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.Springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="www.Springframework.org/schema/beans http://www.Springframework.org/schema/beans/Spring-beans.xsd">
<bean class="com.yhl.myspring.demo.applicationcontext.MyInstantiationAwareBeanPostProcessor"/>
这样的话再使用BeanFactory的方式进行加载的bean在加载时不会有任何改变的,而在使用ApplicationContext方式获取的bean时就会打印出“before”,而这个特性就是咋registryBeanPostProcessor方法中完成的。
我们继续深入分析 AbstractApplicationContext #refresh() 方法中的 registryBeanPostProcessors() 的方法实现:
java"># AbstractApplicationContext
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}

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

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

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

    //使用PriorityOrdered来保证顺序
    List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
    //使用Ordered来保证顺序
    List<String> orderedPostProcessorNames = new ArrayList<>();
    //无序BeanPostProcessor
    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);
        }
    }

    //第一步,注册所有实现了PriorityOrdered的BeanPostProcessor
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

    //注册实现了Ordered的BeanPostProcessor
    List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
    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);

    //注册所有的无序的BeanPostProcessor
    List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
    for (String ppName : nonOrderedPostProcessorNames) {
        BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
        nonOrderedPostProcessors.add(pp);
        if (pp instanceof MergedBeanDefinitionPostProcessor) {
            internalPostProcessors.add(pp);
        }
    }
    registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

    //注册所有的内部BeanFactoryProcessor
    sortPostProcessors(internalPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, internalPostProcessors);

    // Re-register post-processor for detecting inner beans as ApplicationListeners,
    //添加ApplicationListener探测器
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
我们可以看到先从容器中获取所有类型为 BeanPostProcessor.class 的Bean的name数组,然后通过 BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); 获取Bean的实例,最后通过 registerBeanPostProcessors(beanFactory, orderedPostProcessors) 方法将获取到的 BeanPostProcessor 实例添加到容器的属性中,如下:
java"># PostProcessorRegistrationDelegate
private static void registerBeanPostProcessors(
        ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {

    for (BeanPostProcessor postProcessor : postProcessors) {
        beanFactory.addBeanPostProcessor(postProcessor);
    }
}

# AbstractBeanFactory
@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
    Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
    // Remove from old position, if any
    this.beanPostProcessors.remove(beanPostProcessor);
    // Track whether it is instantiation/destruction aware
    if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
        this.hasInstantiationAwareBeanPostProcessors = true;
    }
    if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
        this.hasDestructionAwareBeanPostProcessors = true;
    }
    // Add to end of list
    this.beanPostProcessors.add(beanPostProcessor);
}
可以看到将 beanPostProcessor 实例添加到容器的 beanPostProcessors 属性中。
首先我们会发现,对于 BeanPostProcessor 的处理与 BeanFactoryPostProcessor 极为相似,但也存在不一样的地方。经过对比发现,对于 BeanFactoryPostProcessor 的处理要区分两种情况,一种是通过硬编码方式的处理,另一种是通过配置文件方式的处理。那么为什么在 BeanPostProcessor 的处理中只考虑了配置文件的方式而不考虑硬编码方式呢?那是因为,对于 BeanFactoryPostProcessor 的处理,不但要实现注册,还要实现对后处理器的激活操作,所以需要载入配置中的定义,并进行激活;而 对于 BeanPostProcessor 并不需要马上调用,当然不需要考虑硬编码方式了,只需将配置文件的 BeanPostProcessor 提取出来并注册进 beanFactory 就可以了

6.6.3 初始化message资源

AbstractApplicationContext.class

6.6.4 初始化事件广播器ApplicationEventMulticaster

AbstractApplicationContext.class
(1)Spring 的事件监听的简单用法
在讲解 Spring 的事件广播器之前,我们先来看看 Spring 的事件监听的简单用法
java">//定义监听事件
public class TestEvent extends ApplicationEvent {
    private String msg;
    public TestEvent (Object source){
        super(source);
    }
    public TestEvent (Object source, String msg){
        super(source);
        this.msg = msg;
    }
    public void print (){
        System.out.println(msg);
    }
}

//定义监听器
public class TestListener implements ApplicationListener {
    public void onApplicationEvent (ApplicationEvent event) {
        if (event instanceof TestEvent) {
            TestEvent testEvent = (TestEvent)event;
            testEvent.print();
        }
    }
} 

//配置文件 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.Springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="www.Springframework.org/schema/beans http://www.Springframework.org/schema/beans/Spring-beans.xsd">
<bean id="testListener" class="com.test.event.TestListener"/>

//测试
public class Test {
    public static void main (String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        TestEvent event = new TestEvent("hello", "msg");
        context.publishEvent(event);
    }
}
程序运行时,Spring会将发出的 TestEvent 事件转给我们自定义的 TestListener 进行进一步处理。
我们看看 publishEvent(event) 的源码:
java"># AbstractApplicationContext
protected void publishEvent(Object event, ResolvableType eventType) {
    Assert.notNull(event, "Event must not be null");
    if (logger.isTraceEnabled()) {
        logger.trace("Publishing event in " + getDisplayName() + ": " + event);
    }

    // Decorate event as an ApplicationEvent if necessary
    ApplicationEvent applicationEvent;
    //支持两种事件1、直接继承ApplicationEvent,2、其他时间,会被包装为PayloadApplicationEvent,可以使用getPayload获取真实的通知内容
    if (event instanceof ApplicationEvent) {
        applicationEvent = (ApplicationEvent) event;
    }
    else {
        applicationEvent = new PayloadApplicationEvent<Object>(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) {
        //如果有预制行添加到预制行,预制行在执行一次后被置为null,以后都是直接执行
        this.earlyApplicationEvents.add(applicationEvent);
    }
    else {
        //广播event事件
        getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    }

    // Publish event via parent context as well...
    //父bean同样广播
    if (this.parent != null) {
        if (this.parent instanceof AbstractApplicationContext) {
            ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
        }
        else {
            this.parent.publishEvent(event);
        }
    }
}
主要看 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType) 这行代码 :
java"># SimpleApplicationEventMulticaster
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        Executor executor = getTaskExecutor();
        if (executor != null) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    invokeListener(listener, event);
                }
            });
        }
        else {
            invokeListener(listener, event);
        }
    }
}
查找所有的监听者,依次遍历,如果有线程池,利用线程池进行发送,如果没有则直接发送,如果针对比较大的并发量,我们应该采用线程池模式,将发送通知和真正的业务逻辑进行分离。
我们再进入到 invokeListener() 方法:
java"># SimpleApplicationEventMulticaster
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
    ErrorHandler errorHandler = getErrorHandler();
    if (errorHandler != null) {
        try {
            listener.onApplicationEvent(event);
        }
        catch (Throwable err) {
            errorHandler.handleError(err);
        }
    }
    else {
        try {
            listener.onApplicationEvent(event);
        }
        catch (ClassCastException ex) {
            // Possibly a lambda-defined listener which we could not resolve the generic event type for
            LogFactory.getLog(getClass()).debug("Non-matching event type for listener: " + listener, ex);
        }
    }
}
(2) initApplicationEventMulticaster() ——初始化事件广播器ApplicationEventMulticaster
初始化 ApplicationEventMulticaster 是在方法 initApplicationEventMulticaster() 中实现的,进入到方法体,如下:
java"># AbstractApplicationContext
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    // 1、默认使用内置的事件广播器,如果有的话.
    // 我们可以在配置文件中配置Spring事件广播器或者自定义事件广播器
    // 例如: <bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster"></bean>
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
    }
    // 2、否则,新建一个事件广播器,SimpleApplicationEventMulticaster是spring的默认事件广播器
    else {
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    }
}
通过源码可以看到其实现逻辑与initMessageSource基本相同,其步骤如下:
  1. 查找是否有 name 为 applicationEventMulticaster 的 bean ,如果有,则放到容器里,如果没有,初始化一个系统默认的SimpleApplicationEventMulticaster 放入容器 ;
  2. 查找手动设置的 applicationListeners ,添加到 applicationEventMulticaster 里 ;
  3. 查找定义的类型为 ApplicationListener 的bean,设置到 applicationEventMulticaster
  4. 初始化完成、对 earlyApplicationEvents 里的事件进行通知(此容器仅仅是广播器未建立的时候保存通知信息,一旦容器建立完成,以后均直接通知);
  5. 在系统操作时候,遇到的各种bean的通知事件进行通知 。
可以看到的是 applicationEventMulticaster 是一个标准的观察者模式,对于他内部的监听者applicationListeners,每次事件到来都会一一获取通知。
按照之前介绍的 Spring 的事件监听的简单用法,我们推断,作为广播器,一定是用于存放监听器并在合适的时候调用监听器,那么我们进入默认事件广播器实现 SimpleApplicationEventMulticaster 来一探究竟:
java"># SimpleApplicationEventMulticaster
@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);
      }
   }
}
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);
   }
}
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;
      }
   }
}
可以推断,当产生 Spring 事件时会默认使用 SimpleApplicationEventMulticaster 的 multicastEvent() 方法来广播事件,遍历所有监听器,并使用监听器中的 onApplicationEvent(event) 方法来进行监听器的处理。而对于每个监听器来说其实都可以获取到产生的事件,但是能否进行处理则由事件监听器来决定。

6.6.5 注册监听器

AbstractApplicationContext.class
我们跟进 registerListeners() 方法,代码如下:
java">protected void registerListeners() {
    // Register statically specified listeners first.
    // 首先,注册指定的静态事件监听器,在spring boot中有应用
    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...
    // 如果有早期事件的话,在这里进行事件广播
    // 因为前期SimpleApplicationEventMulticaster尚未注册,无法发布事件,
    // 因此早期的事件会先存放在earlyApplicationEvents集合中,这里把它们取出来进行发布
    // 所以早期事件的发布时间节点是早于其他事件的
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    // 早期事件广播器是一个Set<ApplicationEvent>集合,保存了无法发布的早期事件,当SimpleApplicationEventMulticaster
    // 创建完之后随即进行发布,同时也要将其保存的事件释放
    this.earlyApplicationEvents = null;
    if (earlyEventsToProcess != null) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

6.7 finishBeanFactoryInitialization(beanFactory)——初始化非延迟加载单例

AbstractApplicationContext.class
进入 finishBeanFactoryInitialization(beanFactory) 方法,代码如下:
java"># AbstractApplicationContext
String CONVERSION_SERVICE_BEAN_NAME = "conversionService"; //ConfigurableApplicationContext
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // Initialize conversion service for this context.
    // 判断有无ConversionService(bean属性类型转换服务接口),并初始化
    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 bean post-processor
    // (such as a PropertyPlaceholderConfigurer bean) registered any before:
    // at this point, primarily for resolution in annotation attribute values.
    // 如果beanFactory中不包含EmbeddedValueResolver,则向其中添加一个EmbeddedValueResolver
    // EmbeddedValueResolver-->解析bean中的占位符和表达式
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }

    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    // 初始化LoadTimeWeaverAware类型的bean
    // LoadTimeWeaverAware-->加载Spring Bean时值入第三方模块,如AspectJ
    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.
    // 初始化其他的非延迟加载的单例bean(启动时将所有单例bean提前进行实例化)
    beanFactory.preInstantiateSingletons();
}
我们重点看 beanFactory.preInstantiateSingletons() 方法,可以发现是通过调用 getBean() 方法来初始化的:
java"># DefaultListableBeanFactory
@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) {
                    final 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);
            }
        }
    }
}

6.8 finishRefresh()——完成刷新过程

AbstractApplicationContext.class
通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知,具体代码如下:
java"># AbstractApplicationContext
protected void finishRefresh() {
    // Clear context-level resource caches (such as ASM metadata from scanning).
    // 清空资源缓存
    clearResourceCaches();

    // Initialize lifecycle processor for this context.
    // 初始化生命周期处理器
    //(当ApplicationContext启动或停止时,它会通过LifecycleProcessor来与所有声明的bean的周期做状态更新,LifecycleProcessor在使用前需要初始化)
    initLifecycleProcessor();

    // Propagate refresh to lifecycle processor first.
    // 调用生命周期处理器的onRefresh方法
    getLifecycleProcessor().onRefresh();

    // Publish the final event.
    // 推送容器刷新事件
    //(当完成ApplicationContext初始化时,要通过Spring的事件发布机制来发出ContextRefreshedEvent事件,以保证对应的监听器可以做进一步的逻辑处理)
    publishEvent(new ContextRefreshedEvent(this));

    // Participate in LiveBeansView MBean, if active.
    LiveBeansView.registerApplicationContext(this);
}

http://www.niftyadmin.cn/n/5869229.html

相关文章

prometheus+node_exporter+grafana监控K8S信息

prometheusnode_exportergrafana监控K8S 1.prometheus部署2.node_exporter部署3.修改prometheus配置文件4.grafana部署 1.prometheus部署 包下载地址&#xff1a;https://prometheus.io/download/ 将包传至/opt 解压 tar xf prometheus-2.53.3.linux-amd64.tar.gz 移动到…

华为hcia——Datacom实验指南——二层交换原理

实验配置 eNSP 什么是二层交换 二层交换是指在同一个ip网段内&#xff0c;数据通过二层交换机进行转发。 什么是mac地址 mac地址也叫做硬件地址&#xff0c;是以太网协议的链路层地址。简单的来说&#xff0c;mac地址就是我们硬件的身份证&#xff0c;独一无二。它是由48个bi…

电子商务网站租用香港服务器的好处有哪些?

电子商务网站租用香港服务器的好处主要包括&#xff1a; 香港服务器提供高速的网络连接&#xff0c;国内访问速度优势明显&#xff0c;满足企业内部数据传输和远程办公需求。拥有国际出口带宽优势&#xff0c;实现与全球各地的高速连接&#xff0c;对跨国业务和海外市场拓展至关…

全价值链数字化转型:以美的集团为例,探索开源AI大模型与S2B2C商城小程序源码的融合应用

摘要&#xff1a;在数字经济时代背景下&#xff0c;企业面临着前所未有的竞争压力与市场变革。全价值链的数字化转型&#xff0c;作为提升企业核心竞争力的关键策略&#xff0c;正逐步成为行业共识。美的集团&#xff0c;作为家电行业的领军企业&#xff0c;其基于数字化的全价…

Java 大视界 —— Java 大数据在智慧能源微电网能量管理中的关键技术(100)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

政安晨【零基础玩转各类开源AI项目】DeepSeek 多模态大模型Janus-Pro-7B,本地部署!支持图像识别和图像生成

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 目录 下载项目 创建虚拟环境 安装项目依赖 安装 Gradio&#xff08;UI&#xff09; 运…

特征工程 (Feature Enginering)基础知识2

目录 特征工程数值型特征编码常用的数值型特征处理方法log变换例:广告费用与销量预测区间量化例:根据分位数进行区间量化1、数据预处理Scikit-learn中常用的特征缩放器Scikit-learn中特征缩放器的API2、数据标准化类别型特征编码标签编码独热编码Scikit-learn中的OneHotEncod…

【实战中提升自己】防火墙篇之双ISP切换与VRRP切换对于用户的体验

! 拓扑与说明 某公司的网络架构&#xff0c;这样的架构在目前的网络中是在常见的&#xff0c;假设您接收一个这样的网络&#xff0c;应该如何部署&#xff0c;该实战系列&#xff0c;就是一步一步讲解&#xff0c;如何规划、设计、部署这样一个环境&#xff0c;这…