Spring 系列教程之容器的功能

时间:2022-09-06 23:52:17

Spring 系列教程之容器的功能

经过前面几章的分析,相信大家已经对 Spring 中的容器功能有了简单的了解,在前面的章节中我们一直以 BeanFacotry 接口以及它的默认实现类 XmlBeanFacotry 为例进行分析,但是,Spring 中还提供了另一个接口 ApplicationContext,用于扩展 BeanFacotry 中现有的功能。

ApplicationContext 和 BeanFacotry 两者都是用于加载 Bean 的,但是相比之下, ApplicationContext 提供了更多的扩展功能,简单一点说: ApplicationContext 包含 BeanFactory 的所有功能。通常建议比 BeanFactory 优先,除非在一些限制的场合,比如字节长度对内存有很大的影响时(Applet)绝大多数“典型的”企业应用和系统, ApplicationContext 就是你需要使用的。

那么究竟 ApplicationContext 比 BeanFactory 多出了哪些功能呢?还需要我们进一步的探索。首先我们来看看使用两个不同的类去加载配置文件在写法上的不同。

使用 BeanFactory 方式加载

XmlBeanFacotry bf = new XmlBeanFacotry(new ClassPathResource("spring-context.xm1")):

使用 ApplicationContext 方式加载

XMLApplicationContext bf = new ClassPathXMLApplicationContext("spring-context.xm1");

同样,我们还是以 ClassPathXMLApplicationContext 作为切入点,开始对整体功能进行分析。

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
} public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh,
ApplicationContext parent) throws BeansException { super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}

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

6.1 设置配量路径

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

public void setConfigLocations(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 函数中包含了几乎 ApplicationContext 中提供的全部功能,而上且此函数中逻辑非常清晰明了,使我们很容易分析对应的层次及逻辑。

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备刷新的上下文环境
prepareRefresh(); // Tell the subclass to refresh the internal bean factory.
// 初始化 BeanFactory,并进行 XML 文件读取
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 对 BeanFactory 进行各种功能填充
prepareBeanFactory(beanFactory); try {
// 子类覆盖方法做额外的处理
postProcessBeanFactory(beanFactory); // 激活各种 BeanFactory 处理器
invokeBeanFactoryPostProcessors(beanFactory); // 注册拦截 bean 创建的处理器,这里只是注册,真正的调用是在 getBean 时候
registerBeanPostProcessors(beanFactory); // 为上下文初始化 Message 源,即不同语言的消息体,国际化处理
initMessageSource(); // 初始化应用消息广播器,并放入 ApplicationEventMulticaster 中
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);
} // Destroy already created singletons to avoid dangling resources.
destroyBeans(); // Reset 'active' flag.
cancelRefresh(ex); // Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

下面概括一下 ClassPathXmlApplicationContext 初始化的步骤,并从中解释一下它为我们提供的功能。

(1) 初始化前的准备工作,例如对系统属性或者环境变量进行准备及验证。

在某种情况下项目的使用需要读取某些系统变量,而这个变量的设置很可能会影响着系统的正确性,那么 ClassPathXmlApplicationContext 为我们提供的这个准备函数就显得非常必要,它可以在 Spring 启动的时候提前对必须的变量进行存在性验证

(2) 初始化 BeanFactory,并进行 XML 文件读取。

之前有提到 ClassPathXmlApplicationContext 包含着 BeanFactory 所提供的一切特征,那么在这一步骤中将会复用 BeanFactory 中的配置文件读取解析及其他功能,这一步之后,ClassPathXmlApplicationContext 实际上就已经包含了 BeanFactory 所提提供的功能,也就是可以进行 Bean 的提取等基础操作了。

(3) 对 BeanFactory 进行各种功能填充。

@Qualifier 与 @Autowired 应该是大家非常熟悉的注解,那么这两个注解正是在这一步骤中增加的支持。

(4) 子类覆盖方法做额外的处理。

Spring 之所以强大,为世人所推崇,除了它功能上为大家提供了便例外,还有一方面是它的完美架构,开放式的架构让使用它的程序员很容易根据业务需要扩展已经存在的功能。这种开放式的设计在 Spring 中随处可见,例如在本例中就提供了一个空的函数实现 postProcessBeanFactory 来方便程序员在业务上做进一步扩展。

(5) 激活各种 BeanFactory 处理器。

(6) 注册拦截 bean 创建的 bean 处理器,这里只是注册,真正的调用是在 getbean 时候。

(7) 为上下文初始化 Message 源,即对不同语言的消息体进行国际化处理。

(8) 初始化应用消息广播器,并放人 "applicationeventMulticaster" bean中。

(9) 留给子类来初始化其他的 bean。

(10) 在所有注册的 bean 中查找 listener bean,注册到消息广播器中。

(11) 初始化剩下的单实例(非惰性的)。

(12) 完成刷新过程,通知生命周期处理器 lifecycleProcessor 刷新过程,同时发出 ContextRefreshEvent 通知别人。

6.3 环境准备

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

protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true); if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
} // 留给子类覆盖
initPropertySources(); // 验证需要的属性文件是否都已经放入环境中
getEnvironment().validateRequiredProperties(); // Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}

网上有人说其实这个函数没什么用,因为最后两句代码才是最为关键的,但是却没有什么逻辑处理,initPropertySources 是空的,没有任何逻辑,而 getEnvironment().validateRequiredProperties() 也因为没有需要验证的属性而没有做任何处理。其实这这都是因为没有彻底理解才会这么说,这个函数如果用好了作用还是挺大的。那么,该怎么用呢?我们先探索下各个函数的作用。

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

(2) validateRequiredProperties 则是对属性进行验证,那么如何验证呢?我们举个融合两句代码的小例子来帮助大家理解。

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

public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {

    public MyClassPathXmlApplicationContext(String configLocations) throws BeansException {
super(configLocations);
} public MyClassPathXmlApplicationContext(String path, Class<?> clazz) throws BeansException {
super(path, clazz);
} @Override
protected void initPropertySources() {
// 添加验证要求
getEnvironment().setRequiredProperties("VAR");
}
}

我们自定义了继承自 ClassPathXmlApplicationContext 的 MyClassPathXmlApplicationContext,并重写了 initPropertySources 方法,在方法中添加了我们的个性化需求,那么在验证的时候也就是程序走到 getEnvironment().validateRequiredProperties() 代码的时候,如果系统并没有檢测到对应 VAR 的环境变量,那么将抛出异常。当然我们还需要在使用的时候替换掉原有的

public static void main(String[] args) {
ApplicationContext context = new MyClassPathXmlApplicationContext(
"spring-context-test.xml", Main.class);
MyTestBean myTestBean = (MyTestBean) context.getBean("myTestBean");
System.out.println(myTestBean.getStr());
}

6.4 加载 BeanFactory

obtainFreshBeanFactory 方法从字面理解是获取 BeanFactory。之前有说过, ApplicationContext 是对 BeanFactory 的功能上的扩展,不但但包含了 BeanFactory 的全部功能更在其基础上添加了大量的扩展应用,那么 obtainFreshBeanFactory 正是实现 BeanFactory 的地方,也就是经过了这个函数后 ApplicationContext 就已经拥有了 BeanFactory 的全部功能

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 初始化 BeanFactory,并进行 XML 文件读取,并将得到的 BeanFactory 记录在当前实体的属性中
refreshBeanFactory();
// 返回当前实体的 BeanFactory 属性
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}

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

org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory

protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建 DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory(); // 为了序列化指定id,如果需要的话,让这个 beanFactory 从 id 反序列化到 BeanFactory 对象
beanFactory.setSerializationId(getId());
// 定制 beanFactory,设置相关属性,包括是否允许覆盖同名的不同定义的对象以及循环依赖以及
// 设置 @Autowired 和 @Qualifier 注解解析器 QualifierAnnotationAutowire CandidateResolver
customizeBeanFactory(beanFactory);
// 初始化 DocumentReader,并进行 XML 文件读取及解析
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

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

(1) 创建 DefaultListableBeanFactory 在介绍 BeanFactory 的时候,不知道读者是否还有印象,声明方式为: BeanFactory bf = new XmlBeanFactory(" spring-context-test.xml"),其中的 XmlBeanFactory 继承自 DefaultListableBeanFactory,并提供了 XmlBeanDefinitionReader 类型的 reader 属性,也就是说 DefaultListableBeanFactory 是容器的基础。必须首先要实例化,那么在这里就是实例化 DefaultListableBeanFactory 的步骤。

(2) 指定序列化 ID

(3) 定制 BeanFactory

(4) 加载 BeanDefinition

(5) 使用全局变量记录 BeanFactory 类实例。

因为 DefaultListableBeanFactory 类型的变量 beanFactory 是函数内的局部变量,所以要使用全局变量记录解析结果。

6.4.1 定制 BeanFactory

这里已经开始了对 BeanFactory 的扩展,在基本容器的基础上,增加了是否允许覆盖是否允许扩展的设置并提供了注解 @Qualifier 和 @Autowired 的支持。

org.springframework.context.support.AbstractRefreshableApplicationContext#customizeBeanFactory

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
// 是否允许覆盖同名的不同定义的对象
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 是否允许 bean 之间存在循环依赖
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}

对于允许覆盖和允许依赖的设置这里只是判断了是否为空,如果不为空要进行设置,但是并没有看到在哪里进行设置,究竟这个设置是在哪里进行设置的呢?还是那句话,使用子类覆盖方法,例如:

public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {

    // ...

    @Override
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 就可以支持注解方式的注入了。在讲解根据类型自定注入的时候,我们说过解析 autowire 类型时首先会调用方法:

Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);

因此我们知道,在 QualifierAnnotationAutowireCandidateResolver 中一定会提供了解析 Qualifier 与 Autowire 注解的方法。

org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#getSuggestedValue

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 加载 BeanDefinition

在第一步中提到了将 ClassPathXmlApplicationContext 与 XmlBeanFactory 创建的对比,在实现配置文件的加载功能中除了我们在第一步中已经初始化的 DefaultListableBeanFactory 外,还需要 XmlBeanDefinitionReader 来读取 XML,那么在这个步骤中首先要做的就是初始化 XmlBeanDefinitionReader。

org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
throws BeansException, IOException {
// 为指定的 beanFactory 创建 XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // 对 beanDefinitionReader 进行环境变量的设置
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // 对 beanDefinitionReader 进行设置,可以覆盖
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}

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

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

使用 XmlBeanDefinitionReader 的 loadBeanDefinitions 方法进行配置文件的加载机注册相信大家已经不陌生,这完全就是开始 BeanFactory 的套路。因为在 XmlBeanDefinitionReader 中已经将之前初始化的 Defaultlistable Beanfactory 注册进去了,所以 XmlBeanDefinitionReader 所读取的 BeanDefinitionHolder 都会注册到 DefaultListableBeanfactory 中,也就是经过此步骤,类型 DefaultListableBeanfactory 的变量 beanFactory 已经包含了所有解析好的配置。

6.5 功能扩展

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

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置 beanFactory 的 classLoader 为当前 context 的 classLoader
beanFactory.setBeanClassLoader(getClassLoader()); // 设置 beanFactory 的表达式语言处理器,Spring3 增加了表达式语言的支持
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // 为 beanFactory 增加一个默认的 propertyEditor,这个主要是对 bean 的属性等设置管理的一个工具
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // 添加 BeanPostProcessor
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // 设置了几个忽略自动装配的接口
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(EnvironmentAware.class); // 设置了几个自动装配的特殊规则
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this); // 增加对 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()));
} // 添加默认的系统环境 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) 增加 Aspect的支持(会在第7章中进行详细的讲解)

(7) 将相关环境变量及属性注册以单例模式注册

可能读者不是很理解每个步骤的具体含义,接下来我们会对各个步骤进行详细地分析。

6.5.1 增加SPEL语言的支持

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

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

当然,上面只是列举了其中最简单的使用方式,SPEL 功能非常强大,使用好可以大大提高开发效率,这里只为唤起读者的记忆来帮助我们理解源码,有兴趣的读者可以进一步深人研究。

在源码中通过代码 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())) 注册语言解析器,就可以对 SPEL 进行解析了,那么在注册解析器后 Spring 又是在什么时候调用这个解析器进行解析呢?

之前我们讲解过 Spring 在 bean 进行初始化的时候会有属性填充的一步,而在这一步中 Spring 会调用 Abstractautowirecapablebeanfactory 类的 applyPropertyValues 函数来完成功能。就在这个函数中,会通过构造 BeanDefinitionValueResolver 类型实例 valueResolver 来进行属性值的解析。同时,也是在这个步骤中一般通过 AbstractBeanFactory 中的 evaluateBeanDefinitionString 方法去完成 SPEL 的解析。

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

当调用这个方法时会判断是否存在语言解析器,如果存在则调用语言解析器的方法进行解析,解析的过程是在 Spring 的 expression 的包内,这里不做过多解释。我们通过查看对 evaluateBeanDefinitionString 方法的调用层次可以看出,应用用语言解析器的调用主要是在解析依赖注入 bean 的时候,以及在完成 bean 的初始化和属性获取后进行属性填充的时候。

6.5.2 增加属性注册编辑器

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

public class UserManager {

    private Date data;

    // 省略get/set
}

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

<bean id="userManager" class="UserManager">
<property name="data" value="2018-02-03"/>
</bean>

测试代码:

public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"spring-context-test.xml", Main.class);
System.out.println(context.getBean("userManager"));
}

如果直接这样使用,程序则会报异常,类型转换不成功。因为在 Usermanager 中的 data Value 属性是Date 类型型的,而在 XML中配置的却是 String 类型的,所以当然会报异常。

Spring 针对此问题提供了两种解决办法。

1.使用用自定义属性编辑器

使用自定义属性编辑器,通过继承 PropertyEditorSupport,重写 setastext 方法,具体步骤如下。

(1) 编写自定义的属性编辑器。

import java.beans.PropertyEditorSupport;

public class DatePropertyEdit extends PropertyEditorSupport {
private String format = "yyyy-MM-dd HH:mm:ss"; public void setFormat(String format) {
this.format = format;
} @Override
public void setAsText(String text) throws IllegalArgumentException {
SimpleDateFormat sdf = new SimpleDateFormat(format);
try {
Date date = sdf.parse(text);
this.setValue(date);
} catch (ParseException e) {
;
}
}
}

(2) 将自定义属性编辑器注册到 Spring 中。

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date">
<bean class="spring.context.spring_di.DatePropertyEdit">
<property name="format" value="yyyy-MM-dd"/>
</bean>
</entry>
</map>
</property>
</bean>

在配置文件中引入类型为 CustomEditorConfigurer 的 bean,并在属性 customeditors 中加入自定义的属性编辑器,其中 key 为属性编辑器所对应的类型。通过这样的配置,当 Spring 在注入 bean 的属性时一旦遇到了 java.uti.Date 类型的属性会自动调用自定义的 DatepropertyEditor 解解析器进行解析,并用解析结果代替配置属性进行注入。

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

通过注册 Spring 自带的属性编辑器 CustomDateEditor,具体步骤如下。

(1) 定义属性编辑器

public class DatePropertyEditorRegistar implements PropertyEditorRegistrar {
@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Date.class,
new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
}
}

(2) 注册到 Spring

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="spring.context.spring_di.DatePropertyEditorRegistar"/>
</list>
</property>
</bean>

通过在配置文件中将自定义的 DatePropertyEditorRegistar 注册进人 org.springframework.beans.factory.config.CustomEditorConfigurer 的 propertyEditorRegistrars 属性中,可以具有与方法1同样的效果我们了解了自定义属性编辑器的使用,但是,似乎这与本节中围绕的核心代码 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()))并无联系,因为在注册自定义属性编辑器的时候使用的是 PropertyEditorRegistrar 的 registerCustomEditors 方法,而这里使用的是 ConfigurableListableBeanFactory 的 addPropertyEditorRegistrar 方法。我们不妨深入探索下 ResourceEditorRegistrar 的内部实现,在 ResourceEditorRegistrar 中,我们最关心的方法是 registerCustomEditor

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, InputStream.class, new InputStreamEditor(baseEditor));
doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
doRegisterEditor(registry, File.class, new FileEditor(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);
}
}

在 doRegisterEditor 函数中,可以看到在之前提到的自定义属性中使用的关键代码 registry.registerCustomEditor(requiredType, editor),回过头来看 ResourceEditorRegistrar 类的 registerCustomEditors 方法的核心功能,其实无非是注册了一系列的常用类型的属性编辑器,例如,代码 doRegisterEditor(registry, Class.class, new ClassEditor(classLoader)) 实现的功能就是注册 Class 类对应的属性编辑器。那么,注册后,一且某个实体 bean 中存在一些 Class 类型的属性,那么 Spring 会调用 Classeditor 将配置中定义的 String 类型转换为 Class 类型并进行赋值。

分析到这里,我们不禁有个疑问,虽说 ResourceEditorRegistrar 类的 registerCustomEditors 方法实现了批量注册的功能,但是 beanfactory. ddproperty Editorregistrar(( new Resourceeditor Registra(this,getenvironmentoo) 仅仅是注册了 ResourceEditorRegistrar 实例,却并没有调用 ResourceEditorRegistrar 的 registerCustomEditors 方法进行注册,那么到底是在什么时候进行注册的呢?进进一步查看 ResourceEditorRegistrar 的 registerCustomEditors 方法的调用层次结构,如图6-1所示。

发现在 Abstractbeanfactory 中的 registercustomeditors 方法中被调用过,继续查看 Abstractbeanfactory 中的 registercustomeditors 方法的调用层次结构,如图6-2所示。

其中我们看到一个方法是我们熟悉的,就是 AbstractBeanFactory 类中的 initBeanWrapper 方法,这是在 bean 初始化时使用的一个方法,之前已经使用过大量的篇幅进行讲解,主要是在将 BeanDefinition 转换为 BeanWrapper 后用于对属性的填充。到此,逻辑已经明了,在 bean 的初始化后会调用 ResourceEditorRegistrar 的 registercustomeditors 方法进行批量的通用属性编辑器注册。注册后,在属性填充的环节便可以直接让 Spring 使用这些编抖器进行属性的解析了。

既然提到了 BeanWrapper,这里也有必要强调下, Spring 中用于封装 bean 的是 BeanWrapper 类型,而它又间接继承了 PropertyEditorRegistry 类型,也就是我们之前反复看到的方法参数 PropertyEditorRegistry registry,其实大部分情况下都是 BeanWrapper,对于 BeanWrapper 在 Spring 中的默认实现是 BeanWrapperlmpl,而 BeanWrapperlmpl 除了实现 BeanWrapper 接口外还继承了 PropertyEditorRegistrySupport,在 PropertyEditorRegistrySupport 中有这样一个方法

private void createDefaultEditors() {
this.defaultEditors = new HashMap<Class<?>, PropertyEditor>(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());
this.defaultEditors.put(InputSource.class, new InputSourceEditor());
this.defaultEditors.put(Locale.class, new LocaleEditor());
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());
if (zoneIdClass != null) {
this.defaultEditors.put(zoneIdClass, 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);
}
}

具体的调用方法我们就不去深究了,但是至少通过这个方法我们已经知道了在 Spring中定义了上面一系列常用的属性编辑器使我们可以方便地进行配置。如果我们定义的bean中的某个属性的类型不在上面的常用配置中的话,才需要我们进行个性化属性编辑器的注册。

6.5.3 添加 ApplicationContextAwareProcessor 处理器

了解了属性编辑器的使用后,接下来我们继续通过 AbstractApplicationContext 的 prepareBeanfactory 方法的主线来进行函数跟踪。对于 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)) 其实主要目的就是注册个 BeanPostProcessor,而真正的逻辑还是在 ApplicationContextAwareProcessor 中。

ApplicationContextAwareProcessor 实现 BeanPostProcessor 接口,我们回顾下之前讲过的内容,在 bean 实例化的时候,也就是 Spring 激活 bean 的 init-method 的前后,会调用 BeanPostProcessor 的 postProcessBeforeInitialization 方法和 postProcessAfterInitialization 方法。同样,对于 ApplicationContextAwareProcessor 我们也关心这两个方法。

对于 postProcessAfterInitialization 方法,在 ApplicationContextAwareProcessor 中并没有做过多逻辑处理。

public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}

那么,我们重点看一下 postProcessBeforeInitialization 方法。

public Object postProcessBeforeInitialization(final Object bean, String beanName)
throws BeansException {
AccessControlContext acc = null; if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
} if (acc != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareInterfaces(bean);
return null;
}
}, acc);
}
else {
invokeAwareInterfaces(bean);
} return bean;
} private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
}
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);
}
}
}

postProcessBeforeInitialization 方法中调用了 invokeAwareInterfaces。从 invokeAwareInterfaces 方法中,我们或许已经或多或少了解了 Spring 的用用意,实现这些 Aware 接口的 bean 在被初始化之后,可以取得一些对应的资源。

6.5.4 设置忽略依赖

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

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 设置了几个忽略自动装配的接口
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

6.5.5 注册依赖

Spring 中有了忽略依赖的功能,当然也必不可少地会有注册依赖的功能。

beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

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

6.6 BeanFactory 的后处理

BeanFactory 作为 Spring 中容器功能的基础,用于存放所有已经加载的 bean,为了保证程序上的高可扩展性, Spring 针对 BeanFactory 做了大量的扩展,比如我们熟知的 PostProcessor 等都是在这里实现的。

6.6.1 激活注册的 BeanFactoryPostprocessor

正式开始介绍之前我们先了解下 BeanFactoryPostprocessor 的用法。BeanFactoryPostprocessor 接口跟 BeanPostProcessor 类似,可以对 bean 的定义(配置元数据)进行处理。也就是说, Spring loc 容器允许 BeanFactoryPostprocessor 在容器实际实例化任何其他的 bean 之前读取配置元数据,并有可能修改它。如果你愿意,你可以配置多个 BeanFactoryPostprocessor。你还能通过设置 "order" 属性来控制 BeanFactoryPostprocessor 的执行次序(仅当 BeanFactoryPostprocessor 实现了 Ordered 接口时你才可以设置此属性,因此在实现 BeanFactoryPostprocessor 时,就应当考虑实现 Ordered 接口)请参考 BeanFactoryPostprocessor 和 Ordered 接口的 JavaDoc 以获取更详细的信息。

如果你想改变实际的 bean 实例(例如从配置元数据创建的对象),那么你最好使用 BeanPostprocessor。同样地, BeanFactoryPostprocessor 的作用域范围是容器级的。它只和你所使用的容器有关。如果你在容器中定义一个 BeanFactoryPostprocessor,它仅仅对此容器中的 bean 进行后置处理。 BeanFactoryPostprocessor 不会对定义在另一个容器中的 bean 进行后置处理,即使这两个容器都是在同一层次上。在 Spring 中存在对于 BeanFactoryPostprocessor 的典型应用,比如 PropertyPlaceholderConfigurer。

1. Beanfactory Postprocessor 的典型应用: PropertyPlaceholderConfigurer。 有时候,阅读 Spring 的 Bean 描述文件时,你也许会遇到类似如下的一些配置:

<bean class="com.test.HelloMessage">
<property name="mes">
<value>${bean.message}</value>
</property>
</bean>

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

bean.message=Hi, can you find me?

当访问名为 message 的 bean 时,mes 属性就会被置为字符串 "Hi, can you find me?",但 Spring 框架是怎么知道存在这样的配置文件呢?这就要靠 PropertyPlaceholderConfigurer 这个类的 bean:

<bean id="messageHandler" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>config/conf.properties</value>
</list>
</property>
</bean>

在这个 bea n中指定了配置文件为 config/conf.properties。到这里似乎乎找到问题的答案了,但是其实还有个问题。这个 "meshandler" 只不过是 Spring 框架管理的一个 bean,并没有被别的 bean 或者对象引用, Spring 的 beanFactory 是怎么知道要从这个 bean 中获取配置信息的呢?

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

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

2. 使用自定义 BeanFactoryPostProcessor

我们以实现一个 BeanFactoryPostProcessor,去除潜在的的 "流氓" 属性值的功能来展示自定义 BeanFactoryPostProcessor 的创建及使用,例如 bean 定义中留下 bollocks 这样的字眼。

(1) 配制文件

<?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.xsd"> <bean id="bfpp" class="spring.bean_factory_post_processor.demo2.ObscenityRemovingBeanFactoryPostProcessor">
<property name="obscenties">
<list>
<value>bollocks</value>
<value>winky</value>
<value>bum</value>
<value>Microsoft</value>
</list>
</property>
</bean> <bean id="simplePostProcessor" class="spring.bean_factory_post_processor.demo2.SimplePostProcessor">
<property name="connectionString" value="bollocks"/>
<property name="username" value="imaginecup"/>
<property name="password" value="Microsoft"/>
</bean>
</beans>

(2) ObscenityRemovingBeanFactoryPostProcessor

public class ObscenityRemovingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private Set<String> obscenties; public ObscenityRemovingBeanFactoryPostProcessor() {
this.obscenties = new HashSet<String>();
} @Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
StringValueResolver valueResolver = new StringValueResolver() {
@Override
public String resolveStringValue(String strVal) {
if (isObscene(strVal)) {
return "******";
}
return strVal;
}
};
BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
visitor.visitBeanDefinition(bd);
}
} public boolean isObscene(Object value) {
String potentialObscenity = value.toString().toUpperCase();
return this.obscenties.contains(potentialObscenity);
} public void setObscenties(Set<String> obscenties) {
this.obscenties.clear();
for (String obscenity : obscenties) {
this.obscenties.add(obscenity.toUpperCase());
}
}
}

(3) SimplePostProcessor 实体类

public class SimplePostProcessor {

    private String connectionString;
private String username;
private String password; // 省略get/set/toString
} (4) 测试 ```java
public static void main(String[] args) {
ConfigurableListableBeanFactory bf = new XmlBeanFactory(
new ClassPathResource("spring-context-test.xml", Main.class));
BeanFactoryPostProcessor bfpp = (BeanFactoryPostProcessor) bf.getBean("bfpp");
bfpp.postProcessBeanFactory(bf);
System.out.println(bf.getBean("simplePostProcessor"));
}

输出结果:

SimplePostProcessor{connectionString='', username='imaginecup', password=''}

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

3. 激活 BeanFactoryPostProcessor

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

org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory
beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
}

org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors

public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { // Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<String>(); // 对 BeanDefinitionRegistry 类型的处理
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();
List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =
new LinkedList<BeanDefinitionRegistryPostProcessor>(); // 硬编码注册的后处理器
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryPostProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
// 对于 BeanDefinitionRegistryPostProcessor 类型,在 BeanFactoryPostProcessor 的基础上还有自己定义的方法,需要先调用
registryPostProcessor.postProcessBeanDefinitionRegistry(registry);
registryPostProcessors.add(registryPostProcessor);
}
else {
// 记录常规 BeanFactoryPostProcessor
regularPostProcessors.add(postProcessor);
}
} // PriorityOrdered, Ordered, and the rest.
// 对于配置中读取的 BeanFactoryPostProcessor 的处理
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); // 首页,激活实现 PriorityOrdered 接口的 BeanDefinitionRegistryPostProcessors
List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
registryPostProcessors.addAll(priorityOrderedPostProcessors);
invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry); // 其次,激活实现 Ordered 接口的 BeanDefinitionRegistryPostProcessors
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
List<BeanDefinitionRegistryPostProcessor> orderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(beanFactory, orderedPostProcessors);
registryPostProcessors.addAll(orderedPostProcessors);
invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry); // 最后,剩余的 BeanDefinitionRegistryPostProcessors
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);
registryPostProcessors.add(pp);
processedBeans.add(ppName);
pp.postProcessBeanDefinitionRegistry(registry);
reiterate = true;
}
}
} // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
} else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
} // 在实例化 FactoryBeans 前用 post-processors 处理 FactoryBeans
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); // PriorityOrdered, Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
List<String> orderedPostProcessorNames = new ArrayList<String>();
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
// 对后处理器进行分类
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);
}
} // 首页,激活实现 PriorityOrdered 接口的 BeanFactoryPostProcessor
sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); // 其次,激活实现 Ordered 接口的 BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(beanFactory, orderedPostProcessors);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); // 最后,无序的 BeanFactoryPostProcessor,直接调用
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); // Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}

从上面的方法中我们看到,对于 BeanFactoryPostProcessor 的处理主要分两种情况进行,一个是对于 BeanDefinitionRegistry 类的特殊处理,另一种是对普通的 BeanFactoryPostprocessor 进行子处理。而对于每种情况都需要考虑硬编码注入注册的后处理器以及通过配置注入的后处理器。对于 BeanDefinitionRegistry 类型的处理类的处理主要包括以下内容:

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

org.springframework.context.support.AbstractApplicationContext#addBeanFactoryPostProcessor

public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor
beanFactoryPostProcessor) {
this.beanFactoryPostProcessors.add(beanFactoryPostProcessor);
}

添加后的后处理器会存放在 beanFactoryPostProcessors 中,而在处理 BeanFactoryPostProcessor 时候会首先检测 beanFactoryPostProcessors 是否有数据。当然, BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor,不但有 BeanFactoryPostProcessor 的特性,同时还有自自己定义的个性化方法,也需要在此调用。所以,这里需要从 beanFactoryPostProcessors 中挑出 BeanDefinitionRegistryPostProcessor 的后处理器,并进行其 postProcessBeanDefinitionRegistry 方法的激活。

(2) 记录后处理器主要使用了三个 List 完成。

  • registryPostProcessors:记录通过硬编碣方式注册的 BeanDefinitionRegistryPostProcessor 类型的处理器。

  • regularPostProcessors:记录通过硬编码碣方式注册的 BeanFactoryPostProcessor 类型的处理器。

  • registryPostProcessorBeans:记录通过配置方式注册的 BeanDefinitionRegistryPostProcessor 类型的处理器

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

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

(5)普通 beanFactory 处理

BeanDefinitionRegistryPostProcessor 只对 BeanDefinitionRegistry 类型的 ConfigurableListableBeanfactory 有效,所以如果判断所示的 beanFactory 并不是 BeanDefinitionRegistry,那么便可以忽略 BeanDefinitionRegistryPostProcessor,而直接处理 BeanFactoryPostProcessor,当然获取的方式与上面的获取类似。这里需要提到的是,对于硬编码方式手动添加的后处理器是不需要做任何排序的,但是在配置文件中读取的处理器, Sping 并不保证读取的顺序。所以,为了保证用户的调用顺序的要求, Spring 对于后处理器的调用支持按照 PriorityOrdered 或者 Ordered 的顺序调用。

6.6.2 注册

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

public class MyInstantialtionAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("================");
return null;
} //......
}

在配置文件中添加配置:

<bean class="spring.bean_post_processor.MyInstantialtionAwareBeanPostProcessor"/>

那么使用 BeanFactory 方式进行 Spring 的 bean 的加载时是不会有任何改变的,但是使用 ApplicationContext 方式获取 bean 的时候会在获取每个 bean 时打印出 "================",而这个特性就是在 registerBeanPostProcessors 方法中完成的。我们继续探索 registerBeanPostProcessors 的方法实现。

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

org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors

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<BeanPostProcessor>();
// MergedBeanDefinitionPostProcessor
List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>(); // Ordered 保证顺序
List<String> orderedPostProcessorNames = new ArrayList<String>(); // 无序的 BeanPostProcessor
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
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(beanFactory, priorityOrderedPostProcessors);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); // 第二步:注册所有实现 Ordered 的 BeanPostProcessor
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(beanFactory, orderedPostProcessors);
registerBeanPostProcessors(beanFactory, orderedPostProcessors); // 第三步:注册所有无序的 BeanPostProcessor
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); // 第四步:注册所有 MergedBeanDefinitionPostProcessor 类型的 BeanPostProcessor,并非重复注册
sortPostProcessors(beanFactory, internalPostProcessors);
registerBeanPostProcessors(beanFactory, internalPostProcessors); // 添加 ApplicationListenerDetector
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

配合源码以及注释,在 registerBeanPostProcessors 方法法中所做的逻辑相信大家已经很清楚了,我们再做一下总结。

首先我们会发现,对于 BeanPostProcessor 的处理与 BeanFactoryPostProcessor 的处理极为相似,但是似乎又有些不一样的地方。经过反复的对比发现,对于 BeanPostProcessor 的处理要区分两种情况,一种方式是通过硬编码方式的处理,另一种是通过配置文件方式的处理那么为什么在 BeanPostProcessor 的处理中只考虑了配置文件的方式而不考虑硬编码的方式呢?提出这个问题,还是因为读者没有完全理解两者实现的功能。对于 BeanFactoryPostProcessor 的处理,不但要实现注册功能,而且还要实现对后处理器的激活操作,所以需要载人配置中的定义,并进行激活;而对于 BeanPostProcessor 并不需要马上调用,再说,硬编码的方式实现的功能是将后处理器提取并调用,这里并不需要调用,当然不需要考虑硬编码的方式了,这里的功能只需要将配置文件的的 BeanPostProcessor 提取出来并注册进入 beanFactory 就可以了。

对于 beanFactory 的注册,也不是直接注册就可以的。在 Spring 中支持对于 BeanPostProcessor 的排序,比如根据 Priorityordered 进行排序、根据 Ordered 进行排序或者无序,而 Spring 在 BeanPostProcessor 的激活顺序的时候也会考虑对于顺序的问题而先进行排序。这里可能有个地方读者不是很理解,对于 internalPostProcessors 中存储的后处理器也就是 MergedBeanDefinitionPostProcessor 类型的处理器,在代码中似乎是被重复调用了,如:

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

org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors

private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) { for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}

org.springframework.beans.factory.support.AbstractBeanFactory#addBeanPostProcessor

public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
this.beanPostProcessors.remove(beanPostProcessor);
this.beanPostProcessors.add(beanPostProcessor);
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
}
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
}
}

可以看到,在 registerBeanPostProcessors 方法的实现中其实已经确保了 beanPostProcessor 的唯一性,个人猜想,之所以选择在 registerBeanPostProcessors 中没有进行重复移除操作或许是为了保持分类的效果,使逻辑更为清晰吧。

6.6.3 初始化消息资源

6.6.4 初始化 ApplicationEvnetMulticaster

在讲解 Spring 的时间传播器之前,我们还是先来看一下 Spring 的事件监听的简单用法。

(1) 定义监听事件

public class TestEvent extends ApplicationEvent {
public 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);
}
}

(2) 定义监听器

public class TestListener implements ApplicationListener {

    @Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof TestEvent) {
TestEvent testEvent = (TestEvent) event;
testEvent.print();
}
}
}

(3) 添加配制文件

<!--注册 ApplicationEvnet-->
<bean class="spring.context.application_event.TestListener"/>

(4) 测试

public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"spring-context-test.xml", Main.class);
TestEvent testEvent = new TestEvent("test", "testEvent");
context.publishEvent(testEvent);
}

当程序运行时, Spring 会将发出的 TestEvent 事件转给我们自定义的 TestListener 进行进步处理。或许很多人ー下子会反映出设计模式中的观察者模式,这确实是个典型的应用,可以在比较关心的事件结東后及时处理。那么我们看看 ApplicationEvnetMulticaster 是如何被初始化的,以确保功能的正确运行。

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

  • 如果用户自定义了事件广播器,那么使用用户自定义的事件广播器

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

protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this.applicationEventMulticaster + "]");
}
}
}

按照之前介绍的顺序及逻辑,我们推推断,作为广播器,一定是用于存放监听器并在合适的时候调用监听器,那么我们不妨进入默认的广播器实现 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 方法会真正去调用 listener.onApplicationEvent(event)

protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
listener.onApplicationEvent(event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
listener.onApplicationEvent(event);
}
}

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

6.6.5 初始化监听器

之前在介绍 Spring 的广播器时反复提到了事件监听器,那么在 Spring 注册监听器的时候又做了哪些逻辑操作呢?

protected void registerListeners() {
// 硬编码方式注册的监听器处理
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
} // Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
} // Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}

6.7 初始化非延迟加载单例

完成 BeanFactory 的初始化工作,其中包括 ConversionService 的设置、配置冻结以及非延迟加载的 bean 的初始化工作。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory
beanFactory) {
// Initialize conversion service for this context.
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));
} // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
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); // 冻结所有的 bean 定义,说明注册的 bean 定义将不被修改或任何进一步的处理
beanFactory.freezeConfiguration(); // 初始化剩下的单例(非惰性的)
beanFactory.preInstantiateSingletons();
}

首先我们来了解一下 ConversionService 类所提供的作用。

1. ConversionService 的设置

之前我们提到过使用自定义类型转换器从 String 转换为 Date 的方式,那么,在 Spring 中还提供了另一种转换方式:使用 Converter。同样,我们使用一个简单的示例来了解下 Converter 的使用方式。

(1) 定义转换器

public class String2DateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
try {
return DateUtils.parseDate(source, "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="spring.context.converter.String2DateConverter"/>
</list>
</property>
</bean>

(3) 测试

public static void main(String[] args) {
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new String2DateConverter()); String dateStr = "2018-02-04 00:00:00";
Date date = conversionService.convert(dateStr, Date.class);
System.out.println(date);
}

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

2. 冻结配置

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

org.springframework.beans.factory.support.DefaultListableBeanFactory#freezeConfiguration

public void freezeConfiguration() {
this.configurationFrozen = true;
this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
}

3. 初始化非延迟加载

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

public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("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<String>(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)) {
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
} // Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
smartSingleton.afterSingletonsInstantiated();
return null;
}
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}

6.8 finishRefresh

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

protected void finishRefresh() {
// Initialize lifecycle processor for this context.
initLifecycleProcessor(); // Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh(); // Publish the final event.
publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}

1. initLifecycleProcessor

当 ApplicationContext 启动或停止时,它会通过 initLifecycleProcessor 来与所有声明的 bean 的周期做状态更新,而在 LifecycleProcessor 的使用前首先需要初始化。

protected void initLifecycleProcessor() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
this.lifecycleProcessor =
beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
if (logger.isDebugEnabled()) {
logger.debug("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
}
}
else {
DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
defaultProcessor.setBeanFactory(beanFactory);
this.lifecycleProcessor = defaultProcessor;
beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate LifecycleProcessor with name '" +
LIFECYCLE_PROCESSOR_BEAN_NAME +
"': using default [" + this.lifecycleProcessor + "]");
}
}
}

2. onRefresh

启动所有实现了 Lifecycle 接口的 bean

public void onRefresh() {
startBeans(true);
this.running = true;
} private void startBeans(boolean autoStartupOnly) {
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>();
for (Map.Entry<String, ? extends Lifecycle> entry : lifecycleBeans.entrySet()) {
Lifecycle bean = entry.getValue();
if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
int phase = getPhase(bean);
LifecycleGroup group = phases.get(phase);
if (group == null) {
group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
phases.put(phase, group);
}
group.add(entry.getKey(), bean);
}
}
if (phases.size() > 0) {
List<Integer> keys = new ArrayList<Integer>(phases.keySet());
Collections.sort(keys);
for (Integer key : keys) {
phases.get(key).start();
}
}
}

3. publishEvent

当完成 ApplicationContext 初始化的时候,要通过 Spring 中的事件发布机制来发出 ContextRefreshedEvent 事件,以保证对应的监听器可以做进一步的逻辑处理。

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;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<Object>(this, event);
if (eventType == null) {
eventType = ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, event.getClass());
}
} // Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
} // Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}

Spring 系列教程之容器的功能的更多相关文章

  1. Spring 系列教程之自定义标签的解析

    Spring 系列教程之自定义标签的解析 在之前的章节中,我们提到了在 Spring 中存在默认标签与自定义标签两种,而在上一章节中我们分析了 Spring 中对默认标签的解析过程,相信大家一定已经有 ...

  2. Spring 系列教程之默认标签的解析

    Spring 系列教程之默认标签的解析 之前提到过 Spring 中的标签包括默认标签和自定义标签两种,而两种标签的用法以及解析方式存在着很大的不同,本章节重点带领读者详细分析默认标签的解析过程. 默 ...

  3. 狗鱼IT教程&colon;推介最强最全的Spring系列教程

    Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建. 简单来说,Spring是一个分层的JavaSE/EEfull-stack( ...

  4. Spring系列之IOC容器

    一.概述 IOC容器就是具有依赖注入功能的容器,IOC容器负责实例化.定位.配置应用程序中的对象及建立这些对象之间的依赖.应用程序无需直接在代码中new 相关的对象,应用程序由IOC容器进行组装.在S ...

  5. Spring Security教程&lpar;七&rpar;:RememberMe功能

    在之前的教程中一笔带过式的讲了下RememberMe记住密码的功能,那篇的Remember功能是最简易的配置,其功能和安全性都不强.这里就配置下security中RememberMe的各种方式. 一. ...

  6. Vue &plus; Webpack &plus; Vue-loader 系列教程(1)功能介绍篇

    原文地址:https://lvyongbo.gitbooks.io/vue-loader/content/ Vue-loader 是什么? vue-loader 是一个加载器,能把如下格式的 Vue ...

  7. NGUI3&period;5系列教程之 一些小功能的实现

    (一)可拖动窗体的实现: 1:添加一个Sprite为鼠标点击区域,改名为:DragSprite 2:给DragSprite添加Collider 3:给DragSprite添加Drag Object , ...

  8. Docker系列教程05 容器常用命令

    https://mp.weixin.qq.com/s?__biz=MzI4ODQ3NjE2OA==&mid=2247483890&idx=1&sn=2721f08624e6de ...

  9. Spring Boot2 系列教程&lpar;二&rpar;创建 Spring Boot 项目的三种方式

    我最早是 2016 年底开始写 Spring Boot 相关的博客,当时使用的版本还是 1.4.x ,文章发表在 CSDN 上,阅读量最大的一篇有 43W+,如下图: 2017 年由于种种原因,就没有 ...

随机推荐

  1. socket阻塞与非阻塞,同步与异步、I&sol;O模型,select与poll、epoll比较

    1. 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式: 同步/异步主要针对C端: 同步:      所谓同步,就 ...

  2. Hibernate入门案例 增删改

    一.Hibernate入门案例剖析: ①创建实体类Student 并重写toString方法 public class Student { private Integer sid; private I ...

  3. java 除法向上,向下取整

    向上取整用Math.ceil(double a) 向下取整用Math.floor(double a) // 举例: double a=35; double b=20; double c = a/b; ...

  4. 自定义View 实现软键盘实现搜索

    1. xml文件中加入自定义 搜索view <com.etoury.etoury.ui.view.IconCenterEditText android:id="@+id/search_ ...

  5. QQ登录网站接入

    QQ网站登录是一个非常常用的功能,网上有很多的资料,在此只做一个整理: QQ登录接入也在不断的升级,目前我发布的是2.1,很多资料里显示的那些繁杂的步骤已经不需要了: 第一步需要先申请,申请地址如下: ...

  6. Memcache及telnent命令详解--转

    1.启动Memcache 常用参数memcached 1.4.3-p <num>      设置端口号(默认不设置为: 11211)-U <num>      UDP监听端口 ...

  7. Android&lowbar;HTML解析器&lowbar;jsoup

    jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址.HTML文本内容.它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据. Jsou ...

  8. PHPstorm 如何新增项目

    如何在PHPstorm新增项目 1.打开设置 2.找到Directories ,点击增加路径

  9. &period;NET平台开源项目速览&lpar;19&rpar;Power BI神器DAX Studio

    PowerBI更新频繁,已经有点更不上的节奏,一直在关注和学习中,基本的一些操作大概是没问题,更重要的是注重Power Query,M函数,以及DAX的使用,这才是核心.   上个月研究了DAX的一些 ...

  10. 剑指Offer——网易笔试之解救小易——曼哈顿距离的典型应用

    剑指Offer--网易笔试之解救小易--曼哈顿距离的典型应用 前言 首先介绍一下曼哈顿,曼哈顿是一个极为繁华的街区,高楼林立,街道纵横,从A地点到达B地点没有直线路径,必须绕道,而且至少要经C地点,走 ...