经过之前的分析,我们已经了解了Spring是如何解析和加载的bean的。但是在上一篇文章结束的时候说到,一般我们写程序是不会用到BeanFactory来当做Spring的容器的,一般使用的是ApplicationContext作为Spring的容器。这两者之间有什么区别呢?
ApplicationContext和BeanFactory在Spring中都是用于加载bean的,但是ApplicationContext提供了许多扩展功能,换句话说,BeanFactory有的功能ApplicationContext全都有,而Application有的功能,BeanFactory却不一定有,所有在一般情况下我们写程序用到的都是ApplicationContext作为Spring的容器。
那么,ApplicationContext比BeanFactory多出了哪些功能呢?这就是我们下面要关注的问题。
首先,我们首先来看一看这两个不同的类在加载配置文件上的写法的不同:
使用BeanFactory方式加载XML
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
使用ApplicationContext方式加载XML
ApplicationContext bf = new ClassPathXmlApplicationContext("beanFactoryTest.xml");
与之前研究BeanFactory一样,我们这次还是从ClassPathXmlApplication作为切入点,开始对整体功能进行分析
package org.springframework.context.support;
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
}
设置路径是必不可少的步骤,ClassPathXmlApplicationContext中可以将配置文件路径以数组的方式传入,ClassPathXmlApplicationContext可以对数组进行解析并进行加载。而对于解析及功能的实现都在refresh()中实现。
设置配置路径
在ClassPathXmlApplicationContext中支持多个配置文件以数组方式同时传入:
public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
//解析给定路径
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
此函数主要用于解析给定的路径数组,当然,如果数组中包含特殊符号,如${var},那么在resolvePath中会搜索匹配的系统变量并替换
扩展功能
设置了路径之后,便可以根据路径做配置文件的解析以及各种功能的实现了。可以说refresh函数中几乎包含了ApplicationContext中提供的全部功能,而且此函数中逻辑非常清楚明了,使我们很容易分析对应的层次及逻辑。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//准备刷新的上下文环境
prepareRefresh();
//初始化BeanFactory,并进行XML文件读取
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//对BeanFactory进行各种 功能填充
prepareBeanFactory(beanFactory);
try {
//子类覆盖方法做额外的处理
postProcessBeanFactory(beanFactory);
//激活各种BeanFactory处理器
invokeBeanFactoryPostProcessors(beanFactory);
//注册拦截Bean创建的Bean处理器,这里只是注册,真正的调用是在getBean的时候
registerBeanPostProcessors(beanFactory);
//为上下文初始化Message源,即不同语言的消息体,国际化处理
initMessageSource();
//初始化应用消息广播器,并放入"applicationEventMulticaster"bean中
initApplicationEventMulticaster();
//留给子类来初始化其他的bean
onRefresh();
//在所有注册的bean中查找Listener bean,注册到消息广播中
registerListeners();
//初始化剩下的单实例(非惰性的)
finishBeanFactoryInitialization(beanFactory);
//完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 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)对BeanFatory进行各种功能填充:@Qualifer与@Autowired应该是大家非常熟悉的注解,这两个注解正是在这一步骤中增加的支持
(4)子类覆盖方法做额外的处理:Spring之所以强大,为世人所推崇,除了它功能上为大家提供了便利外,还有一方面就是它的完美架构,开放式的架构让使用它的程序员很容易根据业务需要扩展已经存在的功能。这种开放式的设计在Spring中随处可见,例如在本例中就提供了一个空的函数实现postProcessBeanFactory来方便程序员在业务上做进一步扩展。
(5)激活各种BeanFatory处理器
(6)注册拦截bean创建的bean处理器,这里只是注册,真正的调用是在getBean的时候
(7)为上下文初始化Message源,即对不同语言的消息体进行国际化处理
(8)初始化应用消息广播器,并放入"applicationEventMulticaster"bean中
(9)留给子类来初始化其他的bean
(10)在所有注册的bean中查找listener bean,注册到消息广播器中
(11)初始化剩下的单实例(非惰性的)
(12)完成刷新过程,通知声明周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEven通知别人
环境准备
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<>();
}
有人说其实这个函数没什么用,因为最后两句代码才是最为关键的,但是却没有什么逻辑处理,initPropertySources是空的,没有任何逻辑,而getEnvironment().validateRequiredProperties也因为没有需要验证的属性而没有做任何处理。其实这都是因为没有彻底理解才会这么说,这个函数用好了作用还是很大的。那么,该怎么用呢?我们先探索下各个函数的作用。
(1)initPropertySources:正符合Spring的开放式结构设计,给用户最大扩展Spring的能力。用户可以根据自身的需要重写initPropertySources方法,并在方法中进行个性化的属性处理及设置。
(2)validateRequiredProperties:则是对属性进行验证,那么如何验证呢?我们举个融合两句代码的小例子来帮助大家理解。
假如现在有这样一个需求,工程在运行过程中用到的摸个设置(例如VAR)是从系统环境变量中取得的,而如果用户没有在系统环境变量中配置这个参数,那么工程可能不会工作,这一要求可能会有各种各样的解决办法,当然,在Spring中可以这样做,你可以直接修改Spring的源码,例如修改ClassPathXmlApplicationContext。不过最好的办法还是对源码进行扩展,我们可以自定义类:
public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{
public MyClassPathXmlApplicationContext(String... configLocation){
super(configLocation);
}
protected void initPropertySources(){
getEnvironment().setRequiredProperties("VAR");
}
}
我们自定义了继承自ClassPathXmlApplicationContext的MyClassPathXmlApplicationContext,并重写了initPropertySources方法,在方法中添加了我们的个性化需求,那么在验证的时候也就是程序走到getEnvironment().validateRequiredProperties()代码的时候,如果系统并没有检测到对应VAR的环境变量,那么将抛出异常。当然我们还需要在使用的时候替换掉原有的ClassPathXmlApplicationContext:
public static void main(String[] args){
ApplicationContext bf = new ClassPathXmlApplicationContext("test/customag/test.xml");
User user = (User)bf.getBean("user");
}
加载BeanFactory
obtainFreshBeanFactory方法从字面理解是获取BeanFactory。之前说过,ApplicationContext是对BeanFactory在功能上的扩展,不但包含了BeanFactory的全部功能更在其基础上添加了大量的扩展应用,那么obtainFreshBeanFactory正是实现BeanFactory的地方,也就是经过这个函数后,ApplicationContext正式拥有了BeanFactory的全部功能。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建DefualtListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
//为了序列化指定id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象
beanFactory.setSerializationId(getId());
//定制beanFactory相关属性,包括是否允许覆盖同名称的不同定义的对象以及
//设置@Autowired和@Qualifier注解解析器QualifierAnnotationAutowiredCandidateResolver
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("test.xml"),其中的XmlBeanFactory继承自DefaultListableBeanFactory,并提供了XmlBeanDefinitionReader类型的reader属性,也就是说DefaultListableBeanFactory是容器的基础。必须首先实例化,那么在这里就是实例化DefaultListableBeanFactory的步骤。
(2)指定序列化ID
(3)定制BeanFactory
(4)加载BeanDefinition
(5)使用全局变量BeanFactory类实例
因为DefaultListableBeanFactory类型的变量beanFactory是函数内的局部变量,所以要使用全局变量来记录结果。
定制BeanFactory
这里已经开始了对BeanFactory功能的扩展,在基本容器的基础上,增加了是否允许覆盖是否允许循环依赖。
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
//如果属性allowBeanDefinitionOverriding不为空,设置给beanFactory对象相应属性,
//此属性含义:是否允许覆盖同名称的不同定义的对象
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//如果属性allowCircularReferences不为空,设置给beanFactory对象相应属性,
//此属性含义:是否允许bean之间循环依赖
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
对于允许覆盖和允许循环依赖的设置这里只是判断了是否为空,如果不为空要进行设置,但是并没有看到在哪里进行设置,究竟这个设置是在哪里进行设置的呢?还是那句话,使用子类覆盖方法,例如:
public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory){
super.setAllowBeanDefinitionOverriding(false);
super.setAllowCircularReferences(false);
super.customizeBeanFactory(this.beanFactory);
}
}
设置完后相信大家已经对于这两个属性的使用有所了解,或者可以看前面的文章进行了解。
加载BeanDefinition
在第一步中提到了将ClassPathXmlApplicationContext与XmlBeanFactory创建的对比,在实现配置文件的加载功能中除了我们在第一步已经初始化的DefaultListableBeanFactory外,还需要XmlBeanDefinitionReader来读取XML,那么在这个步骤中首先要做的就是初始化XmlBeanDefinitionReader。
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方法进行配置文件的加载机制注册,后面的代码就又回到了前两篇文章中所分析的流程了,所以这里就不再赘述了。同时,经过此步骤之后,XmlBeanDefinitionReader所读取的BeanDefinitionHolder就都注册到了DefaultListableBeanFactory中了,此时的DefaultListableBeanFactory已经包含了所有解析好的配置了。
功能扩展
进入函数prepareBeanFactory之前,Spring已经完成了对配置的解析,而ApplicationContext在功能上的扩展也由此展开
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//设置beanFactory的classLoader为当前context的classLoader
beanFactory.setBeanClassLoader(getClassLoader());
//设置beanFactory的表达式语言处理器,Spring3增加了表达式语言的支持,
//默认可以使用#{bean.xxx}的形式来调用相关属性值
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
//为beanFactory增加一个默认的propertyEditor,这个主要是对bean的属性等设置管理的一个工具
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
//添加BeanPostProcessor
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
//设置几个忽略自动装配的接口
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
//设置几个自动装配的特殊规则
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
//添加一个ApplicationListenerDetector类型的BeanPostProcessor
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(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.增加AspectJ的支持
7.将相关环境变量及属性注册以单利模式注册。
下面我们来一一的看一下每个步骤的流程
增加SPEL语言的支持
Spring表达式语言全称为"Spring Expression Language",缩写为"SpEL",类似于Struts2x中使用的OGNL表达式语言,能在运行时构建复杂表达式、存取对象图属性、对象方法调用等,并且能与Spring功能完美整合,比如能用来配置bean定义。SpEL是单独模块,只依赖与core模块,不依赖与其他模块,可以单独使用。
SpEL使用#{...}作为定界符,所有在大括号中的字符都将被认为是SpEL,使用格式如下:
<bean id="saxophone" value="com.xxx.xxx.Xxxx" />
<bean>
<property name="instument" value="#{saxophone}"/>
</bean>
相当于:
<bean id="saxophone" value="com.xxx.xxx.Xxxx" />
<bean>
<property name="instrument" ref="saxophone">
</bean>
当然,上面只是列举了其中最简单的使用方式,SpEL功能非常强大,使用好可以大大提高开发效率,这里只是为了帮助我们理解源码,所以不做过多的研究。
在源码中通过代码beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver())注册语言解析器,就可以对SpEL进行解析了,那么在注册解析器后Spring又是在什么时候调用这个解析器进行解析呢?
之前我们说过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的包内,这里不做过多解释。我们通过查看对evaluateBeanDefinitionString方法的调用层次可以看出,应用语言解析器的调用主要是在解析依赖注入bean的时候,以及在完成bean的初始化和属性获取后进行属性填充的时候。
增加属性注册编辑器
在Spring依赖注入的时候可以把普通属性注入进来,但是像Date类型就无法被识别,例如:
public class UserManager{
private Date dataValue;
public Date getDataValue(){
return dataValue;
}
public void setDataValue(Date dataValue){
this.dataValue = dataValue;
}
public String toString(){
return "dataValue = " + dataValue;
}
}
上面代码中,需要对日期型属性进行注入:
<bean id="userManager" class="com.test.UserManager">
<property name="dataValue">
<value>2018-06-30</value>
</property>
</bean>
测试代码:
@Test
public void testDate(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
UserManager userManager = (UserManager)ctx.getBean("userManager");
System.out.println(userManager);
}
如果直接这样使用,程序则会报异常,类型转换不成功。因为在UserManager中的dataValue属性是Date类型的,而在XML中配置的则是String类型的,所以会报异常。
Spring针对这个问题提供了两种解决方法:
1.使用自定义属性编辑器
使用自定义属性编辑器,通过继承PropertyEditorSupport,重写setAsText方法,具体步骤如下:
(1)编写自定义的属性编辑器:
public class DatePropertyEditor extends PropertyEditorSupport{
private String format = "yyyy-MM-dd";
public void setFormat(String format){
this.format = format;
}
public void setAsText(String arg0) throws IllegalArgumentException{
System.out.println("arg0: " + arg0);
SimpleDateFormat sdf = new SimpleDateFormat(format);
try{
Date d = sdf.parse(arg0);
this.setValue(d);
}catch(ParseException e){
e.printStackTrace();
}
}
}
(2)将自定义属性编辑器注册到Spring中:
<bean class="org.Springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date">
<bean class="com.test.DatePropertyEditor">
<property name="format" value="yyyy-MM-dd"/>
</bean>
</entry>
</map>
</property>
</bean>
在配置文件中引入类型为org.Springframework.beans.factory.config.CustomEditorConfigurer的bean,并在属性customEditors中加入自定义的属性编辑器,其中key为属性编辑器所对应的类型。通过这样的配置,当Spring注入bean的属性时一旦遇到了java.util.Date类型的属性会自动调用自定义的DatePropertyEditor解析器进行解析,并用解析结果代替配置属性进行注入。
2.注册Spring自带的属性编辑器CustomDateEditor
通过注册Spring自带的属性编辑器CustomDateEditor,具体步骤如下:
(1)定义属性编辑器
public class DatePropertyEditorRegistrar implements PropertyEditorRegistrar{
public void registerCustomEditors(PropertyEditorRegistry registry){
registry.registerCustomEditors(Date.class, new CustomDateEditor(
new SimpleDateFormat("yyyy-MM-dd"), true)
);
}
}
(2)注册到Spring中
<bean class="org.Springframework.bean.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="com.test.DatePropertyEditorRegistrar" />
</list>
</property>
</bean>
通过在配置文件中将自定义的DatePropertyEditorRegistrar注册进入org.Springframework.beans.factory.config. CustomEditorConfigurer的propertyEditorRegistrars属性中,可以具有与方法1同样的效果。
我们了解了自定义属性编辑器的使用,但是,这似乎与本篇文章中围绕的核心代码beanFactory.addPropertyEditorRegistrar( newResourceEditorRegistrar(this, getEnvironment()))并无联系,因为在注册自定义属性编辑器的时候使用的是PropertyEditor Registry的registerCustomEditor方法,我们不妨深入探索一下ResourceEditorRegistrar的内部实现,在ResourceEditorRegistrar中,我们最关心的方法是registerCustomEditors。
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, Path.class, new PathEditor(baseEditor));
doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor));
doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));
ClassLoader classLoader = this.resourceLoader.getClassLoader();
doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));
if (this.resourceLoader instanceof ResourcePatternResolver) {
doRegisterEditor(registry, Resource[].class,
new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader, this.propertyResolver));
}
}
private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
if (registry instanceof PropertyEditorRegistrySupport) {
((PropertyEditorRegistrySupport) registry).overrideDefaultEditor(requiredType, editor);
}
else {
registry.registerCustomEditor(requiredType, editor);
}
}
在doRegisterEditor函数中,可以看到在之前提到的自定义属性中使用的关键代码:registry.registerCustomEditor(requiredType, editor),回过头来看ResourceEditorRegistrar类的registerCustomEditors方法的核心功能,其实无非是注册了一系列的常用类型的属性编辑器,例如,代码doRegisterEditor(registry, Class.class, new ClassEditor(classLoader))实现的功能就是注册Class类对应的属性编辑器。那么注册后,一旦某个实体bean中存在一些Class类型的属性,那么Spring会调用ClassEditor将配置中定义的String类型转换为Class类型并进行赋值。
分析到这里,我们不禁有个疑问,虽说ResourceEditorRegistrar类的registerCustomEditors方法实现了批量注册的功能,但是bean Factroy.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()))仅仅是注册了ResourceEditor Registrar实例,却并没有调用ResourceEditorRegistrar的registerCustomEditors方法进行注册,那么到底是什么时候进行注册的呢,进一步查看ResourceEditorRegistrar的registerCustomEditors方法的调用层次结构,如图:
image.png
发现在AbstractBeanFactory中的registerCustomEditors方法中被调用过,继续查看AbstractBeanFactory中的register CustomEditors方法的调用层次结构,如图:
image.png其中我们看到了一个熟悉的方法,就是initBeanWrapper方法,这是在bean初始化时使用的一个方法,之前已经使用过大量的篇幅进行讲解,主要是将BeanDefinition转换为BeanWrapper后用于对属性的填充。至此,逻辑已经明了,在bean的初始化后悔调用ResourceEditorRegistrar的registerCustomEditors方法进行批量的通用属性编辑器注册。注册后,在属性填充的环节便可以直接让Spring使用这些编辑器进行属性的解析了。
既然提到了BeanWrapper,这里有必要强调下,Spring用于封装bean的是BeanWrapper类型,而它又间接继承了Property EditorRegistry类型,也就是我们之间反复看到的方法参数PropertyEditorRegistry,其实大部分情况下都是BeanWrapper,对于BeanWrapper在Spring中默认实现是BeanWrapperImpl,而BeanWrapperImpl除了实现BeanWrapper接口外还继承了PropertyEditorRegistrySupport,在PropertyEditorRegistrySupport中有这样一个方法:
private void createDefaultEditors() {
this.defaultEditors = new HashMap<>(64);
// Simple editors, without parameterization capabilities.
// The JDK does not contain a default editor for any of these target types.
this.defaultEditors.put(Charset.class, new CharsetEditor());
this.defaultEditors.put(Class.class, new ClassEditor());
this.defaultEditors.put(Class[].class, new ClassArrayEditor());
this.defaultEditors.put(Currency.class, new CurrencyEditor());
this.defaultEditors.put(File.class, new FileEditor());
this.defaultEditors.put(InputStream.class, new InputStreamEditor());
this.defaultEditors.put(InputSource.class, new InputSourceEditor());
this.defaultEditors.put(Locale.class, new LocaleEditor());
this.defaultEditors.put(Path.class, new PathEditor());
this.defaultEditors.put(Pattern.class, new PatternEditor());
this.defaultEditors.put(Properties.class, new PropertiesEditor());
this.defaultEditors.put(Reader.class, new ReaderEditor());
this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor());
this.defaultEditors.put(TimeZone.class, new TimeZoneEditor());
this.defaultEditors.put(URI.class, new URIEditor());
this.defaultEditors.put(URL.class, new URLEditor());
this.defaultEditors.put(UUID.class, new UUIDEditor());
this.defaultEditors.put(ZoneId.class, new ZoneIdEditor());
// Default instances of collection editors.
// Can be overridden by registering custom instances of those as custom editors.
this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class));
this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));
this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class));
this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));
this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class));
// Default editors for primitive arrays.
this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());
this.defaultEditors.put(char[].class, new CharArrayPropertyEditor());
// The JDK does not contain a default editor for char!
this.defaultEditors.put(char.class, new CharacterEditor(false));
this.defaultEditors.put(Character.class, new CharacterEditor(true));
// Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor.
this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false));
this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true));
// The JDK does not contain default editors for number wrapper types!
// Override JDK primitive number editors with our own CustomNumberEditor.
this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false));
this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true));
this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false));
this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true));
this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false));
this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true));
this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false));
this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true));
this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false));
this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));
this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false));
this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true));
this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));
this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));
// Only register config value editors if explicitly requested.
if (this.configValueEditorsActive) {
StringArrayPropertyEditor sae = new StringArrayPropertyEditor();
this.defaultEditors.put(String[].class, sae);
this.defaultEditors.put(short[].class, sae);
this.defaultEditors.put(int[].class, sae);
this.defaultEditors.put(long[].class, sae);
}
}
具体的调用方法我们就不去深究了,但是至少通过这个方法我们已经知道了在Spring中定义了上面一系列常用的属性编辑器使我们可以方便地进行配置。如果我们定义的bean的某个属性的类型不在上面的常用配置中的话,才需要我们进行个性化属性编辑器的注册。
3.添加ApplicationContextAwareProcessor处理器
了解了属性编辑器的使用后,接下来我们继续回到AbstractApplicationContext的prepareBeanFactory方法的主线来进行函数追踪。对于beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))其实主要目的就是注册BeanPost Processor,而真正的逻辑还是在ApplicationContextAwareProcessor中。
ApplicationContextAwareProcessor实现了BeanPostProcessor接口,我们回顾一下之前的内容,在bean实例化的时候,也就是Spring激活bean的init-method的前后,会调用BeanPostProcessor的postProcessorBeforeInitialization方法和postProcessorAfterInitialization方法,同样,对于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((PrivilegedAction<Object>) () -> {
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(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);
}
}
}
postProcessBeforeInitialization方法中调用了invokeAwareInterfaces。从invokeAwareInterfaces方法中,我们或许已经或多或少了解了Spring的用意,实现这些Aware接口的bean在被初始化之后,可以取得一些对应的资源。
4.设置忽略依赖
当Spring将ApplicationContextAwareProcessor注册后,那么在invokeAwareInterfaces方法中间接调用的Aware类已经不是普通的bean了,如ResourceLoaderAware、ApplicationEventPublisherAware等,那么当然需要再Spring做bean的依赖注入的时候忽略它们。而ignoreDependencyInterfaces的作用正是在此。
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
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实例注入进去
BeanFactory的后处理
BeanFactory作为Spring中容器功能的基础,用于存放所有已经加载的bean,为了保证程序上的高可扩展性,Spring针对BeanFactory做了大量的扩展,比如我们熟知的PostProcessor等都是在这里实现的。
1.激活注册的BeanFactoryPostProcessor
正式开始介绍之前我么你先了解下BeanFactoryPostProcessor的用法。
BeanFactoryPostProcessor接口和BeanPostProcessor类似,可以对bean的定义(配置元数据)进行处理,也就是说,SpringIoC容器允许BeanFactoryPostProcessor在容器实际实例化任何其他的bean之前读取配置元数据,并有可能修改它。如果你愿意,你可以配置多个BeanFactoryPostProcessor。你还可以通过设置"order"属性来控制BeanFactoryPostProcessor的执行次序(仅当BeanFactoryPostProcessor实现了Ordered接口)。具体请参考BeanFactoryPostProcessor和Ordered接口的JavaDoc以获取更详细的信息。
如果你想改变实际的bean实例(例如从配置元数据创建的对象),那么你最好使用BeanPostProcessor。同样的,BeanFactoryPost Processor的作用域范围是容器级的。它只和你所使用的容器有关。如果你在容器中定义一个BeanFactoryPostProcessor,它仅仅对此容器中的bean进行后置处理。BeanFactoryPostProcessor不会对定义在另一个容器中的bean进行后置处理。即使这两个容器在同一个层次上。在Spring中存在对于BeanFactoryPostProcessor的典型应用,比如PropertyPlaceholderConfigurer。
有时候,阅读Spring的Bean描述文件时,我们也许会遇到类似如下的一些配置:
<bean id="message" class="distConfig.HelloMessage">
<property name="mes">
<value>${bean.message}</value>
</property>
</bean>
其中竟然出现了变量引用:${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="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或者对象引用,Spring的beanFactory是怎么知道要从这个bean中获取配置信息的呢?
查看层级结构可以看出PropertyPlaceholderConfigurer这个类间接继承了BeanFactoryPostProcessor接口。这是一个特别的接口,当Spring加载任何实现了这个接口的bean的配置时,都会在bean工厂载入所有bean的配置之后执行PostProcessorBeanFactory方法。在PropertyPlaceholderConfigurer类中实现了postProcessorBeanFactory方法。在mergePorperties、convertProperties、processProperties这3个方法,分别得到配置,将得打的配置转换为合适的类型,最后将配置内容告知BeanFactory。
正是通过实现BeanFactoryPostProcessor接口,BeanFactory会在实例化任何bean之前获得配置信息,从而能够正确解析bean描述文件中的变量引用。
下面我们自定义一个实现了BeanFactoryPostProcessor接口的类来体验一下整个过程。我们通过实现BeanFactoryPostProcessor接口,来去除潜在的“流氓”属性值,例如bean定义下留下bollocks这样的字眼:
<bean id="bfpp" class="com.Spring.test.ObscenityRemovingBeanFactoryPostProcessor">
<property name="obscenties">
<set>
<value>bollocks</value>
<value>winky<value>
<value>bum<value>
<value>Microsoft<value>
</set>
</property>
</bean>
<bean id="simpleBean" class="com.Spring.test.SimplePostProcessor">
<property name="connectionString" value="bollocks" />
<property name="password" value="imaginecup" />
<property name="username" value="Microsoft" />
</bean>
public class ObscenityRemovingBeanFactoryPostProcessor implements BeanFactoryPostProcessor{
private Set<String> obscenties;
public ObscenityRemovingBeanFactoryPostProcessor(){
this.obscenties = new HashSet<String>();
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException{
String[] beanNames = beanFactory.getBeanDefinitionNames();
for(String beanName:beanNames){
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
StringValueResolver valueResolver = new StringValueResolver(){
public String resolveStringValue(String strVal){
if(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 obscenty : obscenties){
this.obscenties.add(obscenty.toUpperCase());
}
}
}
执行类
public class PropertyConfigurerDemo{
public static void main(String[] args){
ConfigurableListableBeanFactory bf = new XmlBeanFactory(new
ClassPathResource("/META-INF/BeanFactory.xml"));
BeanFactoryPostProcessor bfpp = (BeanFactoryPostProcessor)bf.getBean("bfpp");
bfpp.postProcessBeanFactory(bf);
System.out.println(bf.getBean("simpleBean"));
}
}
输出结果
SimplePostProcessor{connectionString=******,username=******,password=imaginecup}
通过ObscenityRemovingBeanFactoryPostProcessor,Spring很好的实现了屏蔽掉obscenties定义的不应该展示的属性。
了解了BeanFactoryPostProcessor的用法后便可以深入研究BeanFactoryPostProcessor的调用过程了。
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//调用 PostProcessorRegistrationDelegate 的 invokeBeanFactoryPostProcessors方法
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
继续调用PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法,我们继续跟踪代码:
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
//对 BeanDefinitionRegistry 类型的处理
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>();
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
//对于 BeanDefinitionRegistryPostProcessor 类型,在 BeanFactoryPostProcessor的
//基础上还有自己定义的方法,需要先调用
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
//记录常规 BeanFactoryPostProcessor
regularPostProcessors.add(postProcessor);
}
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
//对于配置中读取的 BeanDefinitionRegistryPostProcessor 的处理
//首先处理 PriorityOrdered 接口的 BeanDefinitionRegistryPostProcessor
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();
//接着处理 Ordered 接口的 BeanDefinitionRegistryPostProcessor
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();
//最后再处理之前未注册的 BeanDefinitionRegistryPostProcessor
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
//激活所有的 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
//对于配置中读取的 BeanFactoryPostProcessor 的处理
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)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
//按照优先级排序
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
//按照order排序
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
//直接调用
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
//清空缓存
beanFactory.clearMetadataCache();
}
从上面的方法我们可以看到,对于BeanFactoryPostProcessor的处理主要分两种情况进行的,一个是对于BeanDefinitionRegistry类的特殊处理,另一种是对普通的BeanFactoryPostProcessor进行处理。而对于每种情况都需要考虑硬编码注入注册的后处理器以及通过配置注入的后处理器。
对于BeanDefinitionRegistry类型的处理类的处理主要包括以下内容:
(1)对于硬编码注册的后处理器的处理,主要是通过AbstractApplicationContext中的添加处理器方法addBeanFactoryPost Processor进行添加
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
this.beanFactoryPostProcessors.add(postProcessor);
}
添加后的后处理器会存放在beanFactoryPostProcessors里,而在处理BeanFactoryPostProcessor的时候会首先检测beanFactory PostProcessors中是否有数据。当然,BeanDefinitionRegistryPostProcessor继承自BeanFactoryPostProcessor,不但有后者的全部特性,同时还有自己的个性化方法,也需要在此调用。所以,这里需要从beanFactoryPostProcessor中挑出BeanDefinition RegistryPostProcessor的后处理器,并进行其postProcessBeanDefinitionRegistry方法的激活。
(2)记录后处理器主要使用了三个List完成
i.regularPostProcessors:记录通过硬编码方式注册的BeanFactoryPostProcessor类型的处理器
ii.registryProcessors:记录BeanDefinitionRegistryPostProcessor类型的处理器
iii.currentRegistryProcessors:记录当前已经注册过的
BeanDefinitionRegistryPostProcessor类型的处理器。
(3)分别对实现了PriorityOrdered和Ordered接口的BeanDefinitionRegistryPostProcessor类型的处理器进行排序
(4)调用激活方法对处理器进行激活
(5)普通的后处理器的流程与BeanDefinitionRegistryPostProcessor类型的处理器流程大致相同,这里就不再赘述了。
这里需要强调的是,对于硬编码方式手动添加的后处理器是不需要做任何排序的,但是在配置文件中读取的处理器,Spring并不保证读取的顺序。所以,为了保证用户的调用顺序的要求,Spring对于后处理器的调用支持按照PriorityOrdered和Ordered的顺序调用。
2.注册BeanPostProcessor
上文中提到了Bean提到了BeanFactoryPostProcessor的调用,现在我们来探索下BeanPostProcessor,但是这里并不是调用,而是注册。真正的调用其实是在bean的实例化阶段进行的。这是一个很重要的步骤,也是很多功能BeanFactory不支持的重要原因。Spring中大部分功能都是通过后处理器的方式进行扩展的,这是Spring框架的一个特性,但是在BeanFactory中其实并没有实现后处理器的自动注册,所以在调用的时候如果没有进行手动注册其实是不能使用的。但是在ApplicationContext中却添加了自动注册功能,如自定义这样一个后处理器:
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor{
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException{
System.out.println("=====");
return null;
}
}
在配置文件中添加配置:
<bean class="processors.MyInstantiationAwareBeanPostProcessor" />
那么使用BeanFactory方式进行Spring的bean的加载是是不会有任何改变的,但是使用ApplicationContext方式获取bean的时候会在获取每个bean时打印出“====”,而这个特性就是在registerBeanPostProcessor方法中完成的。
我们继续探索registerBeanPostProcessor的方法实现。
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
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和Ordered接口的BeanPostProcessor保证顺序
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 首先排序并注册实现了PriorityOrdered接口的BeanPostProcessor
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// 其次排序并注册实现了Ordered接口的BeanPostProcessor
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// 然后注册正常的BeanPostProcessor
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// 最后排序并注册所有的实现了MergedBeanDefinitionPostProcessor接口的BeanPostProcessor
// 这里并没有重复注册
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// 添加ApplicationListener探测器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
配合源码以及注释,在registerBeanPostProcessor方法中所做的逻辑相信大家都已经很清楚了,我们再做一下总结。
首先我们会发现,对于BeanPostProcessor和BeanFactoryPostProcessor的处理极为相似,但是似乎又有一些不一样的地方。经过反复的对比发现,对于BeanFactoryPostProcessor的处理要区分两种情况,一种方式是通过硬编码方式的处理,另一种是通过配置文件方式的处理。那么为什么在BeanPostProcessor的处理中只考虑了配置文件的方式而不考虑硬编码的方式呢?提出这个问题,还是因为大家没有完全理解两者实现的功能。对于BeanFactoryPostProcessor的处理,不但要实现注册功能,而且还要实现对后处理器的激活操作,所以需要载入配置中的定义,并进行激活:而对于BeanPostProcessor并不需要马上调用,再说,硬编码的方式实现的功能是将后处理器提取并调用,这里并不需要调用当然不需要硬编码的方式了,这里的功能只需要将配置文件的BeanPostProcessor提取出来并注册进入beanFactory就可以了。
对于beanFactory的注册,也不是直接注册就可以的。在Spring中支持对于BeanPostProcessor的排序,比如根据PriorityOrdered进行排序、根据Ordered进行排序或者无序,而Spring在BeanPostProcessor的激活顺序的时候也会考虑对于顺序的问题而先进行排序。
这里有个地方让人很迷惑,对于internalPostProcessor中存储后处理器也就是MergedBeanDefinitionPostProcessor类型的处理器,好像在代码中重复注册了,是这样吗?其实并不是的,我们可以看看对于registerBeanPostProcessor方法的实现方式。
private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}
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的唯一性,个人猜想,之所以选择在registerBeanPostProcessor中没有进行重复移除操作或许是为了保持分类的效果,是逻辑更为清晰吧。
3.初始化消息资源
在进行这段函数的解析之前,我们先来回顾Spring国际化的使用方法。
假设我们正在开发一个支持多国语言的Web应用程序,要求系统能够根据客户端的系统的语言类型返回对应的界面:英文的操作系统返回英文界,而中文的操作系统则返回中文界面——这是典型的i18n国际化问题。对于有国际化要求的应用系统,我们不能简单的采用硬编码的方式编写用户界面信息、报错信息等内容,而必须为这些需要国际化的信息进行特殊处理。简单来说,就是为每种语言提供一种相应的资源文件,并以规范化命名的方式保存在特定的目录中,由系统自动根据客户端语言选择合适的资源文件。
“国际化信息”也称为“本地化信息”,一般需要两个条件才可以确定一个特定类型的本地化信息,它们分别是“语言类型”和“国家/地区的类型”。如中文本地化信息既有中国大陆地区的中文,又有中国台湾地区。中国香港地区的中文,还有新加坡地区的中文。Java通过java.util.Locale类表示一个本地化对象,它允许通过语言参数和国家/地区参数创建一个确定的本地化对象。
java.util.Locale是表示语言和国家/地区信息的本地化类,它是创建国际化应用的基础。下面给出几个创建本地化对象的实例:
//带有语言和国家/地区信息的本地化对象
Locale locale1 = new Locale("zh", "CN");
//只有语言信息的本地化对象
Locale locale2 = new Locale("zh");
//等同于locale1
Locale locale3 = Locale.CHINA;
//等同于locale2
Locale locale4 = Locale.CHINESE;
//获取本地系统默认的本地化对象
Locale locale5 = Locale.getDefault();
JDK的java.util包提供了几个支持本地化的格式化操作工具类:NumberFormat、DateFormat、MessageFormat,而在Spring中的国际化资源操作也无非是对于这些类的封装操作,我们仅仅介绍下MessageFormat的用法以帮助大家回顾
//信息格式化串
String pattern1 = "{0}, 你好!你与{1}在工商银行存入{2}元。";
String pattern2 = "At {1, time, short} On {1, date, long}, {0} paid {2, number, currency}.";
//用于动态替换占位符的参数
Object[] params = {"John", new GregorianCalendar().getTime(), 1.0E3};
//使用默认本地化对象格式化信息
String msg1 = MessageFormat.format(pattern1, params);
//使用指定的本地化对象格式化的信息
MessageFormat mf = new MessageFormat(pattern2, Locale.US);
String msg2 = mf.format(params);
System.out.println(msg1);
System.out.println(msg2);
Spring定义了访问国际化信息的MessageSource接口,并提供了几个易用的实现类。MessageSource分别被HierarchicalMessage Source和ApplicationContext接口扩展,这里我们主要看一下HierarchicalMessageSource接口的几个实现类:
HierarchicalMessageSource接口最重要的两个实现类是ResourceBundleMessageSource和ReloadableResourceBundleMessage Source。它们基于Java的ResourceBundle基础类实现,允许仅通过资源名加载国际化资源。ReloadableResourceBundleMessage Source提供了定时刷新功能,允许在不重启系统的情况下,更新资源信息。StaticMessageSource主要用于程序测试,它允许通过编程的方式提供国家化信息。而DelegatingMessageSource是为方便操作父MessageSource而提供的代理类。仅仅举例ResourceBundleMessageSource的实现方式:
(1)定义资源文件
messages.properties(默认:英文)
test=test
messages_zh_CN.properties(简体中文)
test=测试
(2)定义配置文件
<bean id="messageSource" class="org.Springframework.context.support.ResourceBundleMessageSource">
<property name="basename">
<list>
<value>test/messages</value>
</list>
</property>
</bean>
其中,这个Bean的ID必须命名为messageSource,否则会抛出NoSuchMessageException异常
(3)使用。通过ApplicationContext访问国际化信息。
String[] configs = {"applicationContext.xml"};
ApplicationContext ctx = new ClassPathXmlApplicationContext(configs);
//直接通过容器访问国际化信息
Object[] params = {"John", new GregorianCalendar.getTime()};
String str1 = ctx.getMessage("test", params, Locale.US);
String str2 = ctx.getMessage("test", params, Locale.CHINA);
System.out.println(str1);
System.out.println(str2);
了解了Spring国际化的使用后便可以进行源码的分析了。
在initMessageSource中的方法主要功能是提取配置中定义的messageSource,并将其记录在Spring的容器中,也就是AbstractApplicationContext中,当然,如果用户未设置资源文件的话,Spring中也提供了默认的配置DelegatingMessageSource。
在initMessageSource中获取自定义资源文件的方式为beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, Message Source.class),在这里Spring使用了硬编码的方式硬性规定了自定义资源的文件的ID必须为messageSource,否则便会获取不到自定义资源配置,这也就是为什么前面提到的Bean的id如果不为messageSource会抛出异常。下面来看一下代码:
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
//如果在配置中已经配置了messageSource,那么将messageSource提取并记录在this.messageSource中
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// Make MessageSource aware of parent MessageSource.
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// Only set parent context as parent MessageSource if no parent MessageSource
// registered already.
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isDebugEnabled()) {
logger.debug("Using MessageSource [" + this.messageSource + "]");
}
}
else {
// 如果用户没有定义配置文件,那么使用临时的DelegatingMessageSource以便于调用getMessage方法的返回
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
"': using default [" + this.messageSource + "]");
}
}
}
通过读取并将自定义资源文件配置记录在容器中,那么就可以在获取资源文件的时候直接使用了,例如在AbstractApplicationContext中的获取资源文件属性的方法:
public String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {
return getMessageSource().getMessage(code, args, locale);
}
其中的getMessageSource()方法正是获取了之前定义的自定义资源配置
4.初始化ApplicationEventMulticaster
在讲解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{
public void onApplicationEvent(ApplicationEvent event){
if(event instancof TestEvent){
TestEvent testEvent = (TestEvent)event;
testEvent.print();
}
}
}
(3)添加配置文件
<bean id="testListener" class="com.test.event.TestListener" />
(4)测试
public class Test{
public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
TestEvent event = new TestEvent("hello", "msg");
ctx.publishEvent(event);
}
}
当程序运行时,Spring会将发出的TestEvent事件转给我们自定义的TestListener进行进一步处理。
或许很多人一下子会反应这是设计模式中的观察者模式,这确实是个典型的应用,可以在比较关心的事件结束后及时处理。那么我们看看ApplicationEventMulticaster是如何被初始化的,以确保功能的正确运行。
initApplicationEventMulticaster的方式比较简单,无非考虑两种情况。
i.如果用户自定义了事件广播器,那么使用用户自定义的事件广播器
ii.如果用户没有自定义事件广播器,那么使用默认的ApplicationEventMulticaster。
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, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
可以推断,当产生Spring事件的时候会默认使用SimpleApplicationEventMulticaster的multicasterEvent来广播事件,遍历所有监听器,并使用监听器中的onApplicationEvent方法来进行监听器的处理。而对于每个监听器来说其实都可以获取到产生的时间,但是是否进行处理则由事件监听器决定。
5.注册监听器
之前介绍Spring的广播器时反复提到了事件监听器,那么在Spring注册监听器的时候又做了哪些逻辑操作呢?
protected void registerListeners() {
// 硬编码注册监听器
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 配置文件注册监听器
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);
}
}
}
初始化非延迟加载单例
完成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));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// 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 arg0){
try{
return DateUtil.parseDate(arg0,
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>
(3)测试
这样便可以使用Converter为我们提供的功能了,下面我们通过一个简便的方法来对此直接测试。
public void testString2DateConvert(){
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new String2DateConverter());
String dateStr = "2018-07-04 10:00:00";
Date date = conversionService.convert(dateStr, Date.class);
}
通过以上的功能我们看到了Converter以及ConversionService提供的便利功能,其中的配置就是在当前函数中被初始化的。
2.冻结配置
冻结所有的bean定义,说明注册的bean定义将不被修改或进行任何进一步的处理。
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<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
// 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((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
finishRefresh
在Spring中还提供了Lifecycle接口,Lifecycle中包含了start/stop方法,实现此接口后Spring会保证在启动的时候调用其start方法开始生命周期,并在Spring关闭的时候调用stop方法来结束生命周期,通常用来配置后台程序,在启动后一直运行(如对MQ进行轮询等)。而ApplicationContext的初始化最后正是保证了这一功能的实现。
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches();
// 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.initLifecycleProcess
当ApplicationContext启动或停止时,它会通过LifecycleProcessor来与所有声明的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<>();
lifecycleBeans.forEach((beanName, bean) -> {
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(beanName, bean);
}
});
if (!phases.isEmpty()) {
List<Integer> keys = new ArrayList<>(phases.keySet());
Collections.sort(keys);
for (Integer key : keys) {
phases.get(key).start();
}
}
}
3.publishEvent
当完成ApplicationContext初始化的时候,要通过Spring中的时间发布机制来发出ContextRefreshEvent事件,以保证对应的监听器可以做进一步的逻辑处理。
protected void publishEvent(Object event, @Nullable 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<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
至此,ApplicationContext相比于BeanFactory扩展的功能以及相关代码我们就了解完了,下一篇文章我们将会看一看Spring中另一个重要的思想AOP(面向切面编程)是如何实现的。
网友评论