4、Spring源码-容器的扩展功能

·  阅读 71
4、Spring源码-容器的扩展功能

更多文章请观看:[www.shangsw.com]

一 容器的扩展功能

在前文中我们一直以BeanFactory接口以及它的默认实现类XmlBeanFactory为例进行分析,但是,Spring还提供了另一个接口ApplicationContext,用于扩展BeanFactory中现有的功能。

ApplicationContext和BeanFactory两者都是用于加载bean的,但是相比之下,ApplicationContext提供了更多的扩展功能,它包含BeanFactory的所有功能。通常建议比BeanFactory优先。

使用BeanFactory方式加载XML文件如下:

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
复制代码

使用ApplicationContext方式加载XML:

ApplicationContext context = new ClassPathXmlApplicationContext("beanFactoryTest.xml");
复制代码

同样,我们以ClassPathXmlApplicationContext作为切入点,对整个功能进行分析:

/**
* 创建一个新的ClassPathXmlApplicationContext, 并从XML文件中加载相关的bean定义, 然后自动的刷新上下文
* @param configLocation 配置文件的资源
* @throws BeansException Bean异常
*/
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
   this(new String[]{configLocation}, true, null);
}
复制代码
/**
* 创建ClassPathXmlApplicationContext, 然后从XML文件中加载Bean定义
* @param configLocations 资源文件的数组
* @param refresh         是否自动刷新: 加载所有的Bean定义并创建所有的单例对象
* @param parent          父类
* @throws BeansException Bean异常
*/
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
   super(parent);
   setConfigLocations(configLocations);//设置配置文件
   if (refresh) {
      refresh();//核心功能, 刷新ApplicationContext
   }
}
复制代码

设置路径是必不可少的步骤,ClassPathXmlApplicationContext中可以配置文件路径以数组的方式传入,ClassPathXmlApplicationContext可以对数组进行解析并进行加载,而对于解析及功能实现都在refresh()中

1.1 设置配置路径

在ClassPathXmlApplicationContext中支持多个配置文件以数组方式同时传入:

/**
* 解析配置文件, 并将其配置到configLocations中。
* 如果数组中包含特殊符号, 如${var}这种, 那么resolvePath会搜寻匹配的系统变量并替换
* @param locations location
*/
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中会搜寻匹配的系统变量并替换。

1.2 扩展功能

设置了路径之后,便可以根据路径做配置文件的解析以及各种功能的实现了。可以说refresh函数中包含了几乎ApplicationContext中提供的全部功能:

/**
* 刷新ApplicationContext
* @throws BeansException        bean异常
* @throws IllegalStateException 其他的非法异常
*/
@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {//涉及到并发, 加锁
      prepareRefresh();//准备刷新上下文环境

      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//初始化BeanFactory, 并进行XML文件读取

      prepareBeanFactory(beanFactory);//对BeanFactory进行各种功能填充

      try {
         postProcessBeanFactory(beanFactory);//子类额外的方法做额外的处理

         invokeBeanFactoryPostProcessors(beanFactory);//激活各种BeanFactory的后处理器

         registerBeanPostProcessors(beanFactory);//注册拦截Bean创建的Bean处理器, 这里只是注册, 真正调用是在getBean的时候

         initMessageSource();//为上下文初始化Message源, 即不同语言的消息体, 国际化处理

         initApplicationEventMulticaster();//初始化应用消息广播器, 并放入"applicationEventMulticaster"bean中

         onRefresh();//留给子类初始化其他的Bean

         registerListeners();//在所有注册的bean中查找Listener bean, 注册到消息广播器中

         finishBeanFactoryInitialization(beanFactory);//初始化剩下的单例(非惰性的), 主要是getBean的过程

         finishRefresh();//完成刷新过程, 通知声明周期处理器lifecycleProcessor刷新过程, 同时发出ContextRefreshEvent通知别人
      } catch (BeansException ex) {//出现异常
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }
         destroyBeans();//销毁这个bean

         cancelRefresh(ex);//取消激活的状态

         throw ex;
      } finally {
         resetCommonCaches();//重置公共的缓存
      }
   }
}
复制代码

ClassPathXmlApplicationContext的初始化步骤包括:

  • 初始化前的准备工作,例如对系统属性或者环境变量进行准备及验证。在某种情况下项目的使用需要读取某些系统变量,而这个变量的设置很可能会影响系统的正确性,那么ClassPathXmlApplicationContext提供的这个函数非常必要,它可以在Spring启动的时候提前对必须的变量进行存在性验证
  • 初始化BeanFactory,并进行XML文件读取。这一步中会将复用BeanFactory中的配置文件读取解析及其他功能,这一步之后,ClassPathXmlApplicationContext实际上就包含了BeanFactory所提供的功能
  • 对BeanFactory进行各种功能填充
  • 子类覆盖方法做额外的处理。
  • 激活各种BeanFactory处理器
  • 注册拦截bean创建的bean处理器,这里只是注册,真正的调用是在getBean时候
  • 为上下文初始化Message源,即对不同语言的消息体进行国际化处理
  • 初始化应用消息广播器,并放入“applicationEventMulticaster”bean中
  • 留给子类来初始化其他的bean
  • 在所有注册的bean中查找listener bean,注册到消息广播器中
  • 初始化剩下的单例
  • 完成刷新过程,通知声明周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人

1.3 环境准备

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

/**
* 上下文的刷新准备,
*/
protected void prepareRefresh() {
   this.startupDate = System.currentTimeMillis();//开始时间
   this.closed.set(false);//上下文的关闭状态为false
   this.active.set(true);//上下文的激活状态为true

   //日志打印 Start
   if (logger.isDebugEnabled()) {
      if (logger.isTraceEnabled()) {
         logger.trace("Refreshing " + this);
      } else {
         logger.debug("Refreshing " + getDisplayName());
      }
   }
   //日志打印 End

   initPropertySources();//初始化一些属性(留给子类实现)

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

   //存储预刷新的Listener Start
   if (this.earlyApplicationListeners == null) {
      this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
   } else {
      this.applicationListeners.clear();
      this.applicationListeners.addAll(this.earlyApplicationListeners);
   }
   //存储预刷新的Listener End

   this.earlyApplicationEvents = new LinkedHashSet<>();
}
复制代码
  • initPropertySources符合Spring的开放式结构设计,给用户最大扩展Spring能力。用户可以根据自身的需要重写initPropertySources方法,并在方法中进行个性化的属性处理及设置
  • validateRequiredProperties对属性进行验证。具体怎么验证。如下示例

假如现在有这样一个需求,工程在运行过程中用到的某个设置(例如VAR)是从系统环境变量中取得,而如果用户没有在提供环境变量中配置这个参数,那么工程可能不会工作。这一要求可能有各种各样的解决方法,在Spring中也可以这样做,你可以直接修改Spring的源码,例如修改ClassPathXmlApplicationContext,我们可以自定义类:

public class CustomClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
    public CustomClassPathXmlApplicationContext(String ... configLocations) {
        super(configLocations);
    }

    protected void initPropertySource() {
        getEnvironment().setRequiredProperties("VAR");
    }
}
复制代码

我们自定义了ClassPathXmlApplicationContext,并重写了initPropertySources方法,在方法中添加了个性化需求。如果系统没有检测到对应的VAR环境变量,那么将抛出异常,使用时可以如下:

public static void main(String[] args) {
    ApplicationContext context = new CustomClassPathXmlApplicationContext("test.xml");
    User user = (User)context.getBean("testBean");
}
复制代码

1.4 加载BeanFactory

obtainFreshBeanFactory是实现BeanFactory的地方,也就是经过这个函数后ApplicationContext就已经拥有了BeanFactory的全部功能。

/**
* 刷新内部的BeanFactory
* @return ConfigurableListableBeanFactory
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   refreshBeanFactory();//初始化BeanFactory, 并进行XML文件读取, 并将得到的BeanFactory记录在当前实体的属性中
   return getBeanFactory();//当前实体的BeanFactory属性
}
复制代码

方法中将核心实现委托给了refreshBeanFactory:

/**
* 这个实现是执行一个真实的刷新潜在的上下文BeanFactory: 先关闭上一个BeanFactory(如果存在的话)
* 然后初始化一个新的BeanFactory
* @throws BeansException Bean异常
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
   //如果存在上一个BeanFactory Start
   if (hasBeanFactory()) {
      destroyBeans();//销毁所有的缓存(包括objectSingletons: 三级缓存)
      closeBeanFactory();//关闭这个BeanFactory
   }
   //如果存在上一个BeanFactory End

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

refreshBeanFactory的主要功能有:

  • 创建DefaultListableBeanFactory。我们之前介绍,声明XmlBeanFactory,其中的XmlBeanFactory继承自DefaultListableBeanFactory,并提供了XmlBeanDefinitionReader类型的reader属性,也就是说DefaultListableBeanFactory是容器的基础。必须首先要实例化
  • 指定序列化ID
  • 定制BeanFactory
  • 加载BeanDefinition
  • 使用全局变量记录BeanFactory类实例

1.4.1 定制BeanFactory

这里已经开始对BeanFactory的扩展,在基本容器的基础上,增加了是否允许覆盖是否允许循环引用:

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
   if (this.allowBeanDefinitionOverriding != null) {
      beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
   }

   if (this.allowCircularReferences != null) {
      beanFactory.setAllowCircularReferences(this.allowCircularReferences);
   }
}
复制代码

1.4.2 加载BeanDefinition

程序到这里其实还没有读取XML配置文件,所以这里需要XmlBeanDefinitionReader来读取XML,函数loadBeanDefinitions就是对XmlBeanDefinitionReader做初始化的:

/**
* 加载BeanDefinitions
* @see XmlBeanDefinitionReader
* @see #initBeanDefinitionReader(XmlBeanDefinitionReader)
* @param beanFactory beanFactory
* @throws BeansException Bean异常
* @throws IOException IO异常
*/
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {

   XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);//为指定BeanFactory创建XmlBeanDefinitionReader

   beanDefinitionReader.setEnvironment(this.getEnvironment());//环境变量的设置
   beanDefinitionReader.setResourceLoader(this);//资源加载器
   beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

   initBeanDefinitionReader(beanDefinitionReader);//对BeanDefinitionReader进行设置, 可以覆盖
   loadBeanDefinitions(beanDefinitionReader);//触发加载逻辑
}
复制代码

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

/**
* 通过给定的XmlBeanDefinitionReader加载BeanDefinition。
* 这个方法的声明周期是由{@link #refreshBeanFactory()}方法控制
* @param reader XmlBeanDefinitionReader
* @throws BeansException Bean异常
* @throws IOException IO异常
*/
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方法进行配置文件的加载机注册其实我们之前已经知道了,这完全就是BeanFactory的内容。

1.5 功能扩展

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

/**
* 对BeanFactory(DefaultListableBeanFactory)进行功能填充
* @param beanFactory BeanFactory(DefaultListableBeanFactory)
*/
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   beanFactory.setBeanClassLoader(getClassLoader());//设置beanFactory的classLoader为当前context的classLoader

   /*
    * 设置beanFactory的表达式语言处理器, Spring 3增加了表达式语言的支持,
    * 默认可以使用#{bean.xxx}的形式调用相关属性的值
    */
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

   //为beanFactory增加一个默认的propertyEditor, 这个主要是对bean的属性等设置管理的一个工具
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));//添加BeanPostProcessor

   //设置几个忽略自动装配的接口 Start
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
   //设置几个忽略自动装配的接口 End

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

   //注册一个BeanPostProcessor
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

   //增加对AspectJ的支持 Start
   if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }
   //增加对AspectJ的支持 End

   //添加默认的系统bean Start
   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());
   }
   //添加默认的系统bean End
}
复制代码

上面函数中主要进行了几个方面的扩展:

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

1.5.1 增加SPEL语言的支持

Spring表达式语言全称为“Spring Expression Language”,缩写为:“SpEL”,能在运行时构建复杂表达式、存储对象图属性、对象方法调用等,并且能与Spring功能完美整合。SpEL是单独模块,只依赖于core模块,不依赖于其他模块,可以单独使用。

SpEL使用#{...}作为定界符,所有在大括号中的字符都被认定为SpEL,使用格式如下:

<bean id="saxophone" value="com.xxx.xx.xxx"/>
<bean>
    <property name="instrument" value="#{saxophone}"/>
</bean>
复制代码

相当于:

<bean id="saxophone" value="com.xxx.xx.xxx"/>
<bean>
    <property name="instrument" ref="saxophone"/>
</bean>
复制代码

当然,上面只是最简单的示例,SpEL功能非常强大,使用好可以大大提高开发效率。

在源码中通过代码beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver()) 注册语言解析器,就可以对SpEL进行解析了。

这个其实是Spring在bean进行初始化的时候会有属性填充的一部,而在这一步Spring会调用AbstractAutowireCapableBeanFactory类的applyPropertyValues函数来完成功能,就在这个函数中,会通过BeanDefinitionValueResolver类型实例valueResolver来进行属性值的解析,同时,也就是在这一步通过AbstractBeanFactory中的evaluateBeanDefinitionString方法去完成SpEL解析的:

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));
}
复制代码

当调用这个方法时会判断是否存在语言解析器,如果存在则调用语言解析器的方法进行解析,解析的过程是在Spring的expression的包内。这里不做过多解释。

1.5.2 增加属性注册编辑器

在Spring DI注入的时候可以把普通属性注入进来,但是像Date类型就无法识别了,例如:

public class UserManager {
    private Date date;

    //getter  setter

}
复制代码

上面代码中,需要对日期属性进行注入:

<bean id="userManager" class="test.UserManager">
    <property name="date">
        <value>2021-07-28</value>
    </property>
</bean>
复制代码

此时测试时会报异常,类型转换不成功。因为在UserManager中的date是Date类型,而XML中配置却是String类型,所以会报异常。Spring针对此问题可以使用自定义属性编辑器解决。

使用自定义属性编辑器,通过继承PropertyEditorSupport,重写setAsText方法

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 d = sdf.parse(arg0);
            this.setValue(d);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}
复制代码

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

<bean class="org.Springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="customEditors">
        <map>
            <entry key="java.util.Date">
                <bean class="test.DatePropertyEditor">
                    <property name="format" value="yyyy-MM-dd"/>
                </bean>
            </entry>
        </map>
    </property>
</bean>
复制代码

通过这样,当Spring在注入bean的属性时一旦遇到了java.util.Date类型的属性会自动调用自定义的DatePropertyEditor解析器进行解析,并用解析结果代替属性进行注入。

1.5.3 添加ApplicationContextAwareProcessor处理器

对于beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))这段代码,主要的目的就是注册BeanPostProcessor,而真正的逻辑还是在ApplicationContextAwareProcessor中

ApplicationContextAwareProcessor实现了BeanPostProcessor接口。在bean实例化的时候,Spring激活bean的init-method的前后,会调用BeanPostProcessor的postProcessBeforeInitialization方法和postProcessAfterInitialization方法。而ApplicationContextAwareProcessor中对于postProcessAfterInitialization并没有重写,而只是重写了postProcessBeforeInitialization方法:

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)){
      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 ApplicationContextAware) {
      ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
   }
}
复制代码

从invokeAwareInterfaces方法中,实现了这些Aware接口的bean在被初始化之后,可以取得一些对应的资源

1.5.4 设置忽略依赖

当Spring将ApplicationContextAwareProcessor注册后,那么在invokeAwareInterfaces方法中间接调用的Aware类已经不是普通的bean了,如ApplicationEventPublisherAware等,那么Spring做bean的依赖注入时候忽略它们,而ignoreDependencyInterface 的作用就是在此:

beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
复制代码

1.5.5 注册依赖

Spring中有了忽略依赖的功能,也就会有注册依赖的功能:

beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
复制代码

1.6 BeanFactory的后处理

BeanFactory作为Spring中容器的基础,用于存放所有已经加载bean,为了保证程序上的高扩展性,Spring针对BeanFactory做了大量的扩展,比如PostProcessor等。

1.6.1 激活注册BeanFactoryPostProcessor

首先,我们了解一下BeanFactoryPostProcessor用法:

BeanFactoryPostProcessor接口跟BeanPostProcessor类似,可以对bean的定义进行处理。也就是说,Spring IoC容器允许BeanFactoryPostProcessor在容器实际实例化任何其他的bean之前读取配置元数据,并可能修改它。也可以配置多个BeanFactoryPostProcessor,可以通过实现Ordered接口实现执行顺序。

如果想要改变实际的bean实例,那么最好使用BeanPostProcessor。BeanFactoryPostProcessor的作用域范围是容器级的,它之和你所使用的容器有关。如果你在容器中定义一个BeanFactoryPostProcessor,它仅仅对此容器中的bean进行后处理。Spring中存在对于BeanFactoryPostProcessor的典型应用,比如PropertyPlaceholderConfigurer。

1.6.1.1 PropertyPlaceholderConfigurer

有一些Spring的描述文件,会遇到如下一些配置:

<bean id="message" class="test.HelloMessage">
    <property name="mes">
        <value>${bean.message}</value>
    </property>
</bean>
复制代码

其中出现了变量引用:${bean.message}。这就是Spring的分散配置,可以在另外的配置文件中为bean.message指定值,如在bean.property配置定义:

bean.message=Hi
复制代码

当访问名为message的bean时,mes属性就会被置为字符串“Hi”,此时Spring就是靠PropertyPlaceholderConfigurer这类的bean:

<bean id="mesHandler" class="org.Springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>config/bean.properties</value>
        </list>
    </property>
</bean>
复制代码

在这个bean中指定了配置文件为config/bean.properties。这个mesHandler只不过是Spring框架管理的一个bean,并没有被别的bean或者对象引用。

PropertyPlaceholderConfigurer这个类间接继承了BeanFactoryPostProcessor接口,当Spring加载任何实现了这个接口的bean的配置时,都会在bean工厂载入所有bean的配置之后执行postProcessorBeanFactory方法。在PropertyResourceConfigurer类中实现了postProcessBeanFactory方法,在方法中先后调用了mergeProperties、convertProperties、processProperties这三个方法,分别得到了配置,将得到的配置转换为合适的类型,最后将配置内容告知BeanFactory。

正式通过实现BeanFactoryPostProcessor接口,BeanFactory会在实例化任何bean之前获得配置信息,从而能够正确解析bean描述文件中的变量引用。

1.6.1.2 使用自定义BeanFactoryPostProcessor

我们实现一个BeanFactoryPostProcessor,去除潜在的不合规的属性值的功能,例如bean定义中留下bollocks这样的字眼。

定义ObscenityRemoveingBeanFactoryPostProcessor:

public class ObsenityRemovingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    /** 不规范词汇的集合 */
    private Set<String> obscenties;

    public ObsenityRemovingBeanFactoryPostProcessor() {
        this.obscenties = new HashSet<>();
    }

    public void setObscenties(Set<String> obscenties) {
        this.obscenties.clear();
        this.obscenties = obscenties.stream().map(str -> str.toLowerCase(Locale.ROOT)).collect(Collectors.toSet());
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();//所有的BeanDefinition配置的beanName
        for (String beanName : beanDefinitionNames) {
            BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
            StringValueResolver valueResolver = strVal -> isObscene(strVal) ? "*****" : strVal;
            BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
            visitor.visitBeanDefinition(bd);
        }
    }

    /**
     * 判断是否是不规范的词汇
     * @param val 数据
     * @return true/false
     */
    private boolean isObscene(Object val) {
        return obscenties.contains(val.toString().toLowerCase(Locale.ROOT));
    }
}
复制代码

配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<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-4.0.xsd">
    <bean id="bfpp" class="com.bianjf.context.ObsenityRemovingBeanFactoryPostProcessor">
        <property name="obscenties">
            <set>
                <value>bollocks</value>
                <value>winky</value>
                <value>bum</value>
                <value>Microsoft</value>
            </set>
        </property>
    </bean>

    <bean id="simplePostProcessor" class="com.bianjf.context.SimplePostProcessor">
        <property name="connectionStr" value="bollocks"/>
        <property name="password" value="123456"/>
        <property name="userName" value="Microsoft"/>
    </bean>
</beans>
复制代码

测试代码如下:

public class BeanFactoryPostProcessorTest {
    public static void main(String[] args) {
        ConfigurableListableBeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryProcessorTest.xml"));
        BeanFactoryPostProcessor bfpp = (BeanFactoryPostProcessor) bf.getBean("bfpp");
        bfpp.postProcessBeanFactory(bf);
        System.out.println("结果: " + bf.getBean("simplePostProcessor"));
    }
}
复制代码

输出结果如下:

结果: SimplePostProcessor{connectionStr='*****', password='123456', userName='*****'}
复制代码

通过ObscenityRemovingBeanFactoryPostProcessor Spring很好实现了屏蔽掉obscenties定义的不应该展示的属性。

1.6.1.3 激活BeanFactoryPostProcessor

了解了BeanFactoryPostProcessor的用法后便可以深入研究BeanFactoryPostProcessor的调用过程了:

/**
* 实例化并且执行所有已经注册的BeanFactoryPostProcessor实例, 并且顺序可以保证。
* @param beanFactory ConfigurableListableBeanFactory
*/
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
   PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

   if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }
}
复制代码
/**
* 激活BeanFactoryPostProcessor
* @param beanFactory               ConfigurableListableBeanFactory
* @param beanFactoryPostProcessors 注册的BeanFactoryPostProcessor
*/
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
   Set<String> processedBeans = new HashSet<>();

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

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

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

      String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
      for (String ppName : postProcessorNames) {
         if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
            processedBeans.add(ppName);
         }
      }
      sortPostProcessors(currentRegistryProcessors, beanFactory);
      registryProcessors.addAll(currentRegistryProcessors);
      invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
      currentRegistryProcessors.clear();

      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);
      currentRegistryProcessors.clear();

      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);
         currentRegistryProcessors.clear();
      }

      invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
      invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
   } else {
      invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
   }

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

   List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
   List<String> orderedPostProcessorNames = new ArrayList<>();
   List<String> nonOrderedPostProcessorNames = new ArrayList<>();
   for (String ppName : postProcessorNames) {
      if (processedBeans.contains(ppName)) {
      } 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);
      }
   }

   sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
   invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

   List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
   for (String postProcessorName : orderedPostProcessorNames) {
      orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
   }
   sortPostProcessors(orderedPostProcessors, beanFactory);
   invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

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

   beanFactory.clearMetadataCache();
}
复制代码

从上面的代码中可以看到,对于BeanFactoryPostProcessor的处理主要分两种情况,一个是对于BeanDefinitionRegistry类的特殊处理,另一种是对普通的BeanFactoryPostProcessor进行处理。

(1) 对于硬编码注册的后处理器的处理,主要是通过AbstractApplicationContext中添加处理器方法addBeanFactoryPostProcessor进行添加:

public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor) {
    this.beanFactoryPostProcessors.add(beanFactoryPostProcessor);
}
复制代码

添加后的处理器存放在beanFactoryPostProcessors中,而在处理BeanFactoryPostProcessor时候会首先检测beanFactoryPostProcessors是否有数据。

(2) 记录后处理器主要使用三个list完成:

  • registryPostProcessors:记录通过硬编码方式注册的BeanDefinitionRegistryPostProcessor类型的处理器
  • regularPostProcessors:记录通过硬编码方式注册的BeanFactoryPostProcessor类型的处理器
  • registryPostProcessorBeans:记录通过配置方式注册的BeanDefinitionRegistryPostProcessor类型的处理器

(3) 对以上所记录的List中的后处理器进行统一调用BeanFactoryPostProcessor的postProcessBeanFactory方法

(4) 对beanFactoryPostProcessors中非BeanDefinitionRegistryPostProcessor类型的后处理器进行统一的BeanFactoryPostProcessor的postProcessBeanFactory方法调用

(5) 普通beanFactory处理

1.6.2 注册BeanPostProcessor

上文提到了BeanFactoryPostProcessors的调用,现在我们看BeanPostProcessor。但是这里并不是调用,而是注册。真正的调用其实是在bean的实例化阶段进行的。这是一个很重要的步骤,也是很多功能BeanFactory不支持的重要原因。Spring中大部分功能都是通过后处理器的方式进行扩展的,这是Spring框架的一个特性。但是在BeanFactory中其实并没有实现后处理器的自动注册,所以在调用的时候如果没有进行手动注册其实是不能使用的。

如下,是我们自定义一个后处理器:

public class CustomBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("CustomBeanPostProcessor.postProcessBeforeInitialization -- beanName: " + beanName);
        return bean;
    }
}
复制代码

在配置文件中添加配置:

<bean id="customBeanPostProcessor" class="com.bianjf.context.CustomBeanPostProcessor"/>
复制代码

那么使用BeanFactory方式进行Spring的bean的加载时不会有任何变化,但是使用ApplicationContext方式获取bean的时候会在获取每个bean时会打印自定义的内容,而这个特性就是在registerBeanPostProcessors方法中完成的:

/**
* 初始化和注册所有的BeanPostProcessor
* @param beanFactory BeanFactory
*/
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
   PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
复制代码
/**
* 注册BeanPostProcessor
* @param beanFactory beanFactory
* @param applicationContext applicationContext
*/
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));


   List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();//使用PriorityOrdered保证顺序
   List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
   List<String> orderedPostProcessorNames = new ArrayList<>();//使用Ordered保证顺序
   List<String> nonOrderedPostProcessorNames = new ArrayList<>();//无序BeanPostProcessor
   for (String ppName : postProcessorNames) {
      if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {//PriorityOrdered
         BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
         priorityOrderedPostProcessors.add(pp);
         if (pp instanceof MergedBeanDefinitionPostProcessor) {
            internalPostProcessors.add(pp);
         }
      } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {//Ordered
         orderedPostProcessorNames.add(ppName);
      } else {
         nonOrderedPostProcessorNames.add(ppName);
      }
   }

   //第一步, 注册所有实现ProirityOrdered的BeanPostProcessor Start
   sortPostProcessors(priorityOrderedPostProcessors, beanFactory);//排序
   registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);//注册
   //第一步, 注册所有实现ProirityOrdered的BeanPostProcessor End

   //第二部, 注册所有实现Ordered的BeanPostProcessor Start
   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);//注册
   //第二部, 注册所有实现Ordered的BeanPostProcessor End

   //第三步, 注册所有无序的BeanPostProcessor Start
   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);
   //第三步, 注册所有无序的BeanPostProcessor End

   //最后一步, 注册所有MergedBeanDefinitionPostProcessor的BeanPostProcessor(并非重复注册) Start
   sortPostProcessors(internalPostProcessors, beanFactory);
   registerBeanPostProcessors(beanFactory, internalPostProcessors);
   //最后一步, 注册所有MergedBeanDefinitionPostProcessor的BeanPostProcessor(并非重复注册) End

   //添加ApplicationListener探测器
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
复制代码

配合注释,在registerBeanPostProcessors方法中所做的逻辑其实已经很清楚了。

在Spring中支持对于BeanPostProcessor的排序,比如根据PriorityOrdered进行排序、根据Ordered进行排序或者无序,而Spring在BeanPostProcessor的激活顺序的时候也会考虑对于顺序的问题而先进行排序。

1.6.3 初始化ApplicationEventMulticaster

Spring的事件传播器的使用我这里就不多做介绍了,具体可以看:

21、Spring Event事件驱动模型

这里我们看看ApplicationEventMulticaster是如何被初始化的,以确保功能的正确运行。

initApplicationEventMulticaster的方式比较简单,无非考虑两种情况:

  • 如果用户自定义了事件广播器,那么使用用户自定义的事件广播器
  • 如果用户没有自定义事件广播器,那么使用默认的ApplicationEventMulticaster

代码如下:

/**
* 初始化ApplicationEventMulticaster
* 如果一级缓存中不存在ApplicationEventMulticaster, 则创建SimpleApplicationEventMulticaster
*/
protected void initApplicationEventMulticaster() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {//如果已经存在这个ApplicationEventMulticaster
      this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);//直接使用
      if (logger.isTraceEnabled()) {
         logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
      }
   } else {//缓存中不存在
      this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);//创建一个SimpleApplicationEventMulticaster
      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(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())) {
         Log logger = LogFactory.getLog(getClass());
         if (logger.isTraceEnabled()) {
            logger.trace("Non-matching event type for listener: " + listener, ex);
         }
      } else {
         throw ex;
      }
   }
}
复制代码

可以推断,当产生Spring事件的时候会默认使用SimpleApplicationEventMulticaster的multicastEvent来广播事件,遍历所有监听器,并使用监听器中的onApplicationEvent方法来进行监听器的处理。而对于每个监听器来说都可以获取到产生的事件,但是是否进行处理则由事件监听器来决定。

1.6.4 注册监听器

在上面介绍Spring的广播器的时候提到了事件监听器,那么在Spring注册监听器的函数registerListeners时候代码如下:

/**
* 注册监听器
*/
protected void registerListeners() {
   //硬编码方式注册的监听器处理 Start
   for (ApplicationListener<?> listener : getApplicationListeners()) {
      getApplicationEventMulticaster().addApplicationListener(listener);
   }
   //硬编码方式注册的监听器处理 End

   //配置文件注册的监听器处理 Start
   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
   for (String listenerBeanName : listenerBeanNames) {
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
   }
   //配置文件注册的监听器处理 End

   Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
   this.earlyApplicationEvents = null;
   if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
         getApplicationEventMulticaster().multicastEvent(earlyEvent);
      }
   }
}
复制代码

1.7 初始化非延迟加载单例

完成BeanFactory的初始化工作,其中包括ConversionService的设置、配置冻结以及非延迟加载的bean的初始化工作。finishBeanFactoryInitialization函数代码如下:

/**
* 初始化非延迟加载的单例。初始化剩下所有的单例Bean
* @param beanFactory BeanFactory
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
   //初始化ConversionService设置 Start
   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));
   }
   //初始化ConversionService设置 End

   if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
   }

   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
   for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
   }

   beanFactory.setTempClassLoader(null);

   //冻结所有的Bean定义, 说明注册的Bean定义将不被修改或任何进一步的处理
   beanFactory.freezeConfiguration();

   //初始化剩下的单例Bean(非惰性的)
   beanFactory.preInstantiateSingletons();
}
复制代码

1.7.1 ConversionService的设置

之前我们提到过使用自定义类型转换器从String转换为Date的方式,那么,在Spring中还提供了另一种转换方式:使用Converter

我们先看一个示例:

(1) 定义转换器

public class String2DateConvert implements Converter<String, Date> {
    @Override
    public Date convert(String source) {
        try {
            return DateUtils.parseDate(source, new String[]{"yyyy-MM-dd HH:mm:ss"});
        } catch (ParseException e) {
            return null;
        }
    }
}
复制代码

(2) 注册

<bean id="conversionService" class="org.Springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="String2DateConverter"/>
        </list>
    </property>
</bean>
复制代码

通过以上的功能,我们看到Converter以及ConversionService提供的便利功能,其中的配置就是在当前函数中被初始化的。

1.7.2 冻结配置

冻结所有的bean定义,说明注册的bean定义将不被修改或进行任何进一步的处理:

/**
* 冻结所有的Bean定义, 说明注册的Bean将不会被修改或者任何进一步的处理
*/
@Override
public void freezeConfiguration() {
   this.configurationFrozen = true;
   this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
}
复制代码

1.7.3 初始化非延迟加载

ApplicationContext实现的默认行为就是在启动时将所有单例bean提前进行实例化。提前实例化意味着作为初始化过程的一部分,ApplicationContext实例会创建并配置所有的单例bean。通常情况下这是一件好事,因为这样在配置中的任何错误就会即刻被发现(否则可能要花几个小时甚至几天)。这个过程就是在preInstantiateSingletons中完成的:

/**
* 初始化非延迟加载
* ApplicationContext实现的所有行为就是启动时将所有Bean提前进行实例化, 这时会创建并配置所有的单例Bean。
* 通常情况下这是一件好事, 因为在配置中有错误会即刻被发现。
* 其实主要就是getBean()的前置处理
* @throws BeansException Bean异常
*/
@Override
public void preInstantiateSingletons() throws BeansException {
   if (logger.isTraceEnabled()) {
      logger.trace("Pre-instantiating singletons in " + this);
   }

   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

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

   for (String beanName : beanNames) {
      Object singletonInstance = getSingleton(beanName);
      if (singletonInstance instanceof SmartInitializingSingleton) {
         SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
         if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
               smartSingleton.afterSingletonsInstantiated();
               return null;
            }, getAccessControlContext());
         } else {
            smartSingleton.afterSingletonsInstantiated();
         }
      }
   }
}
复制代码

1.8 finishRefresh

在Spring中还提供了Lifecycle接口,Lifecycle中包含start/stop方法,实现此接口后Spring会保证在启动的时候调用其start方法开始生命周期,并在Spring关闭的时候调用stop方法来结束生命周期,通常用来配置后台程序。而ApplicationContext的初始化最后正是保证这一功能的实现:

/**
* 完成上下文的刷新: 执行LifecycleProcessor的onRefresh()方法并且发布ContextRefreshedEvent
*/
protected void finishRefresh() {
   //清除上下文级别的Resource缓存
   clearResourceCaches();

   //初始化LifeCycleProcessor
   initLifecycleProcessor();

   //调用LifecycleProcessor的onRefresh()方法
   getLifecycleProcessor().onRefresh();

   //发布Event
   publishEvent(new ContextRefreshedEvent(this));

   // Participate in LiveBeansView MBean, if active.
   LiveBeansView.registerApplicationContext(this);
}
复制代码
分类:
后端
标签:
分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改