Spring源码系列 - ApplicationContext容器的功能扩展
- 前言
- 一. ApplicationContext容器
- 二. 总结
前言
在我Spring源码系列的前几篇文章中,看过的读者可能会发现,对于Spring的容器,我一直用的是BeanFactory。而本文将讲解Spring的另一个常用的容器ApplicationContext。ApplicationContext拥有BeanFactory的全部功能,同时扩展类许多的功能。两种都是用来加载Bean的一种容器。
例如,BeanFactory加载XML:(该用法过时了)
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("user.xml"));
ApplicationContext加载XML:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("user.xml");
一. ApplicationContext容器
我们从上述的案例代码出发,来看下源码:
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
	this(new String[] {configLocation}, true, null);
}
↓↓↓↓↓↓
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
	// 1.父类构造
	super(parent);
	// 2.设置配置文件的路径
	setConfigLocations(configLocations);
	if (refresh) {
		// 3.核心功能
		refresh();
	}
}
1.1 拓展功能refresh
ApplicationContext的拓展功能,必定是在解析到对应的配置文件的基础上进行的,而上述构造函数中,我们看到的方法只有refresh()函数了,这里面包含了ApplicationContext容器中几乎所有的功能。我们来分析下其源码:
@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
		// 1.刷新上下文环境,做一些准备工作,如对系统属性或者环境变量进行验证
		prepareRefresh();
		// 2.初始化BeanFactory,进行XML读取。此步骤结束后,ApplicationContext就拥有了BeanFactory的功能。
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
		// 3.对BeanFactory进行填充,对 @Qualifier 和 @Autowired 注解进行支持
		prepareBeanFactory(beanFactory);
		try {
			// 4.处理子类覆盖方法
			postProcessBeanFactory(beanFactory);
			StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
			// 5.激活各种BeanFactory处理器
			invokeBeanFactoryPostProcessors(beanFactory);
			// 6.注册 [拦截bean的创建过程] 的处理器
			registerBeanPostProcessors(beanFactory);
			beanPostProcess.end();
			// 7.为上下文初始化Message,国际化处理
			initMessageSource();
			// 8.初始化应用消息广播器
			initApplicationEventMulticaster();
			// 9.让子类来初始化其他的bean
			onRefresh();
			// 10.在已经注册的bean中寻找监听器,并注册到消息广播器中
			registerListeners();
			// 11.初始化非惰性单例bean
			finishBeanFactoryInitialization(beanFactory);
			// 12.完成刷新过程
			finishRefresh();
		}
		catch (BeansException ex) {
			// ...
			// 若失败了,则销毁该bean,并且重置刷新状态
			destroyBeans();
			cancelRefresh(ex);
			throw ex;
		}
		finally {
			resetCommonCaches();
			contextRefresh.end();
		}
	}
}
此时,我们就根据上面的标注来进行解析。
1.2 环境准备
此时我们关注第一步prepareRefresh();看看它做了什么事情:
protected void prepareRefresh() {
	// ...省略
	// 1.让子类去覆盖,一般初始化完成后,内容交给第二步来校验
	initPropertySources();
	// 2.验证需要的属性文件是否都已经加载到环境中了
	getEnvironment().validateRequiredProperties();
	// ...省略
}
这里我将大部分不重要的代码给省略了,留下了俩核心方法:
- initPropertySources()
- validateRequiredProperties()
遗憾的是,点开initPropertySources方法,发现源码是空的:
protected void initPropertySources() {
	// For subclasses: do nothing by default.
}
那么这个环境准备的函数,里面的操作又是空的,那到底有啥用呢?
案例1
项目结构如下:(Spring源码中测试的话,建议在context包下,自己测试的话,记得引以下spring-context包)
 
 自定义的容器MyApplicationContext,需要继承ClassPathXmlApplicationContext:
public class MyApplicationContext extends ClassPathXmlApplicationContext {
	public MyApplicationContext(String... configLocations) throws BeansException {
		super(configLocations);
	}
	protected void initPropertySources() {
		getEnvironment().setRequiredProperties("ljj");
	}
}
User类:
public class User {
	private String name;
	private String address;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
}
Test类:
public class Test {
	@org.junit.jupiter.api.Test
	void test(){
		MyApplicationContext context = new MyApplicationContext("test.xml");
		User user = (User) context.getBean("user");
		System.out.println(user.getName());
	}
}
test.xml文件:
<?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-3.0.xsd">
	<bean name="user" class="test.User">
		<property name="name" value="11"/>
	</bean>
</beans>
测试如下:
 
 那么如何让程序成功跑通嘞?我们增加个环境配置参数:
 
 随便填什么,主要是ljj的参数名称就行,我填了ljj="真棒",再跑一次程序,结果如下:
 
 此时我们就知道initPropertySources和validateRequiredProperties方法的作用了,就是用来校验我们自己配置的环境变量的。
1.3 加载BeanFactory
紧接着,我们里看下拓展功能里的第二步,初始化BeanFactory操作。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
↓↓↓↓↓
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		// 1.初始化BeanFactory,进行XML读取
		refreshBeanFactory();
		// 2.返回BeanFactory实体类对象
		return getBeanFactory();
	}
}
我们来看下第一步refreshBeanFactory()方法。首先其是AbstractApplicationContext类中的一个抽象方法,并没有具体的实现,因此该方法最终会委派给子类AbstractRefreshableApplicationContext来完成:
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
	@Override
	protected final void refreshBeanFactory() throws BeansException {
		// 1.若已经存在BeanFactory实例,则销毁,重新生成一个
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			// 2.创建DefaultListableBeanFactory实例
			// 注意,我们的案例中,XmlBeanFactory是DefaultListableBeanFactory的一个子类。
			// 因此DefaultListableBeanFactory可以说是容器的基础了。
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			// 3.序列化指定的id,若有必要,将从该id进行反序列化得到一个BeanFactory对象
			beanFactory.setSerializationId(getId());
			// 4.定制BeanFactory,设置相关的属性。例如:是否允许覆盖同名称的不同定义的对象、循环依赖、@Autowired、@Qualifier注解等
			customizeBeanFactory(beanFactory);
			// 5.初始化DocumentReader,进行XML的读取和解析
			loadBeanDefinitions(beanFactory);
			// 6.将完成好的BeanFactory赋值
			this.beanFactory = beanFactory;
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
}
其中我们先来重点看下第四步:定制BeanFactory:
customizeBeanFactory(beanFactory);
↓↓↓↓↓↓
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
	// allowBeanDefinitionOverriding:是否允许覆盖同名称的不同定义的对象
	// 若其部位null,则设置对应的属性
	if (this.allowBeanDefinitionOverriding != null) {
		beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	// allowCircularReferences:是否允许bean之间存在循环依赖
	if (this.allowCircularReferences != null) {
		beanFactory.setAllowCircularReferences(this.allowCircularReferences);
	}
}
同样,在这里没有做任何具体的实现,只是单单的进行赋值罢了,那么这段代码又有什么作用呢?同理,和案例1同样,该方法若希望真正发挥作用,同样需要我们自定义一个子类去完成,例如:
public class MyApplicationContext extends ClassPathXmlApplicationContext {
	public MyApplicationContext(String... configLocations) throws BeansException {
		super(configLocations);
	}
	protected void initPropertySources() {
		getEnvironment().setRequiredProperties("ljj");
	}
	// 设置不允许覆盖名称的不同定义的对象以及不允许发生循环依赖
	protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
		super.setAllowBeanDefinitionOverriding(false);
		super.setAllowCircularReferences(false);
	}
}
紧接着,在定制完自己的Spring容器后(重写customizeBeanFactory方法),来看下第五步:加载BeanDefinition做了什么事情。同样loadBeanDefinitions方法,也是AbstractApplicationContext类中的一个抽象方法,并没有具体的实现,因此该方法最终会委派给子类AbstractXmlApplicationContext去完成:
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
	// 1.为指定的BeanFactory创建一个XmlBeanDefinitionReader
	XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
	// 2.对XmlBeanDefinitionReader进行环境变量的设置。
	beanDefinitionReader.setEnvironment(this.getEnvironment());
	beanDefinitionReader.setResourceLoader(this);
	beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
	// 3.允许对BeanDefinitionReader进行覆盖
	initBeanDefinitionReader(beanDefinitionReader);
	// 4.BeanDefinition的加载
	loadBeanDefinitions(beanDefinitionReader);
}
对于最后一步loadBeanDefinitions,本文不再详细展开,有需要则开启传送门:Spring源码系列:容器的基本实现
那么在这里对1.3节做个总结,ApplicationContext容器对BeanFactory的加载阶段做了什么事情,很简单,两步:
- 进行功能的拓展,用户可自定义属性,是否允许覆盖名称的不同定义的对象以及bean之间发生发生循环依赖。
- 加载BeanDefinition。(做和BeanFactory一样的事情)
1.4 功能的拓展(BeanFactory的属性填充)
从1.3小节我们可以知道,完成BeanFactory的加载之后,此时ApplicationContext容器已经完成了对配置的解析和BeanDefinition的加载。已经可以正常地去获取Bean了。那么此时,也是时候对容器的功能进行拓展了。我们来看下第三步prepareBeanFactory(beanFactory);
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// 1.设置BeanFactory的类加载器为当前context的类加载器
	beanFactory.setBeanClassLoader(getClassLoader());
	// 2.设置BeanFactory的表达式语言处理器。
	if (!shouldIgnoreSpel) {
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
	}
	// 3.为BeanFactory增加一个propertyEditor,用于对bean属性的管理
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
	// 4.配置BeanPostProcessor以及几个忽略自动装配的接口
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
	beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
	beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
	beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
	beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);
	// 5.设置几个自动装配的特殊规则
	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
	beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
	beanFactory.registerResolvableDependency(ApplicationContext.class, this);
	// 注册监听器类型的bean
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
	// 6.增加对AspectJ的支持。(AOP)
	if (!NativeDetector.inNativeImage() && 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());
	}
	if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
		beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
	}
}
做的事情分为这么几种:
- 增加对SpEL语言的支持。
- 增加对属性编辑器的支持。
- 增加一些内置类,以及设置依赖注入可以忽略的接口。
- 注册一些固定依赖的属性以及系统相关的bean。
- 增加AspectJ的支持。
1.4.1 SpEL语言支持
Spring表达式的全称为:Spring Expression Language,缩写SpEL。用于在运行时构建复杂的表达式、存取对象图属性、对象方法调用等。可以用来配置bean的定义。其使用#{...}作为定界符。
我们先来看下案例:
 User类:
public class User {
	private String name;
	private String path;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPath() {
		return path;
	}
	public void setPath(String path) {
		this.path = path;
	}
}
Test类:
public class Test {
	@org.junit.jupiter.api.Test
	void test(){
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spel/test.xml");
		User user = (User) context.getBean("user");
		System.out.println(user.getName());
		System.out.println(user.getPath());
	}
}
test.xml文件:我们通过表达式动态地为 userBean 注入 osName(操作系统名)与 classPath(类路径)属性。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:p="http://www.springframework.org/schema/p"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
	<bean id="user" class="test.spel.User"
		  p:name="#{systemProperties['os.name']}"
		  p:path="#{systemProperties['java.class.path']}"/>
</beans>
结果如下:
 
1.4.2 增加属性注册编辑器
背景:Spring进行属性注入的时候,注入int、String这类属性,是可以正常注入的,但是像Date类型就无法被识别,例如:
我们在上述的案例基础上修改下:
 test.xml:
<bean id="user" class="test.spel.User">
	<property name="date" value="2022-03-16"/>
</bean>
User类:
public class User {
	private Date date;
	public Date getDate() {
		return date;
	}
	public void setDate(Date date) {
		this.date = date;
	}
}
Test类:
@org.junit.jupiter.api.Test
void test(){
	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spel/test.xml");
	User user = (User) context.getBean("user");
	System.out.println(user.getDate());
}
运行结果如下:
 
针对这种情况,Spring提供了两种解决方法:
(1) 使用自定义属性编辑器
这种方式,需要我们编写自定义的属性编辑器,继承PropertyEditorSupport类,重写其setAsText方法。案例如下:
DatePropertyEditor类:
import java.beans.PropertyEditorSupport;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DatePropertyEditor extends PropertyEditorSupport {
	@Override
	public void setAsText(String text) throws IllegalArgumentException {
		System.out.println("自定义解析Date,解析前:" + text);
		try {
			SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
			Date date = dateFormat.parse(text);
			this.setValue(date);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
test.xml文件增加bean配置:在customEditors属性中注入自定义的属性编辑器。(注意:该属性的类型是个Map,因此用了Map标签,同时entry的key应该指的是Date类型,意思是一旦遇到了该类型的属性,就会调用自定义的DatePropertyEditor进行解析)
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
	<property name="customEditors">
		<map>
			<entry key="java.util.Date" value="test.spel.DatePropertyEditor"/>
		</map>
	</property>
</bean>
结果如下:
 
(2) 利用Spring自带的CustomDateEditor编辑器
案例如下:
创建DateEditorRegister类,同时实现PropertyEditorRegistrar接口:
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateEditorRegister implements PropertyEditorRegistrar {
	@Override
	public void registerCustomEditors(PropertyEditorRegistry registry) {
		registry.registerCustomEditor(Date.class,
				new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
	}
}
test.xml文件更改如下:改为注入propertyEditorRegistrars属性
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
	<property name="propertyEditorRegistrars">
		<list>
			<bean class="test.spel.DateEditorRegister"/>
		</list>
	</property>
</bean>
结果依旧如上图所示,这里就不展开了。
1.4.3 添加ApplicationContextAwareProcessor处理器
这里我们关注第四步代码块:
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);
这行代码的作用就是注册一个BeanPostProcessor,它有啥作用呢?
在调用bean的initMethod方法前后分别调用postProcessBeforeInitialization和postProcessAfterInitialization方法,那么我们来看下ApplicationContextAwareProcessor处理器做了什么:
class ApplicationContextAwareProcessor implements BeanPostProcessor {
	// postProcessAfterInitialization方法没有重写,就默认的什么都不干返回bean,这里就不说了
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		// 这里的类型都是上文希望忽略的依赖接口,调用了ignoreDependencyInterface方法。
		// 如果不是这几种bean,直接返回
		if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
				bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
				bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
				bean instanceof ApplicationStartupAware)) {
			return bean;
		}
		AccessControlContext acc = null;
		if (System.getSecurityManager() != null) {
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}
		if (acc != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				// 核心调用
				invokeAwareInterfaces(bean);
				return null;
			}, acc);
		}else {
			// 核心调用
			invokeAwareInterfaces(bean);
		}
		return bean;
	}
	private void invokeAwareInterfaces(Object bean) {
		// 这里就是对各种类型的bean,添加各种资源属性而已
		if (bean instanceof EnvironmentAware) {
			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
		}
		if (bean instanceof EmbeddedValueResolverAware) {
			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
		}
		if (bean instanceof ResourceLoaderAware) {
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		}
		if (bean instanceof ApplicationEventPublisherAware) {
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
		if (bean instanceof MessageSourceAware) {
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		}
		if (bean instanceof ApplicationStartupAware) {
			((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
		}
		if (bean instanceof ApplicationContextAware) {
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}
}
提问:为何要设置忽略依赖,即调用ignoreDependencyInterface方法?
答:Spring将ApplicationContextAwareProcessor注册后,在invokeAwareInterfaces方法调用的Aware类已经不是普通的bean。例如EnvironmentAware类,那么需要在Spring做bean的依赖注入的时候忽略他们。他们不适用于一般bean的依赖注入。有另外的逻辑做处理。
总结下,添加ApplicationContextAwareProcessor处理器的作用也就是:让一些实现了Aware接口的bean,在初始化的时候能够获得对应的资源。
例如某bean实现了EnvironmentAware接口,那么就会执行这段代码,添加当前容器的系统环境相关属性:
if (bean instanceof EnvironmentAware) {
	((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
关于对AspectJ的支持,将在后续文章中讲解。
1.5 BeanFactory的后处理
这一环节,我们将跳出prepareBeanFactory()代码,回到refresh()代码,同时定位到第五步,激活各种BeanFactory处理器:
invokeBeanFactoryPostProcessors(beanFactory);
首先,我们来了解下BeanFactoryPostProcessor是干啥用的。一般用来在实例化一个bean之前,读取相关元数据并进行修改操作。 Spring中就已经有对BeanFactoryPostProcessor的一个应用:PropertyPlaceholderConfigurer类。
1.5.1 Spring中BeanFactoryPostProcessor的应用
User类:
public class User {
	private String address;
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
}
Test类:
@org.junit.jupiter.api.Test
void test(){
	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
	User user = (User) context.getBean("user");
	System.out.println(user.getAddress());
}
然后在resources下创建目录config,并创建文件bean.properties:
 
message=Hello World
text.xml文件如下:
<?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-3.0.xsd">
	<bean id="mesHandler" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<list>
				<value>config/bean.properties</value>
			</list>
		</property>
	</bean>
	<bean name="user" class="test.User">
		<!--这里的message则是个变量,最终从配置的config/bean.properties文件中读取-->
		<property name="address" value="${message}"/>
	</bean>
</beans>
程序运行结果如下:
 
 从结果而言,我们能看出PropertyPlaceholderConfigurer类的作用,也就是指定了配置文件的地址。我们来看下这个类的层次结构:
 
 可见其间接地继承了BeanFactoryPostProcessor接口,而当Spring加载了任何实现了该接口的bean后,都会在bean工厂载入所有bean之后,调用postProcessBeanFactory方法。
我们来看下PropertyResourceConfigurer类中对postProcessBeanFactory方法的重写:
public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport
		implements BeanFactoryPostProcessor, PriorityOrdered {
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		try {
			// 合并配置
			Properties mergedProps = mergeProperties();
			// 转换配置
			convertProperties(mergedProps);
			// 将配置信息载入到BeanFactory工厂里,也是因此,
			// BeanFactory在实例化前能得到配置信息,而正确的解析我们XML配置文件中的变量引用
			processProperties(beanFactory, mergedProps);
		}
		// ..catch
	}
}
1.5.2 自定义BeanFactoryPostProcessor
自定义MyPostProcessor类,做一个敏感词屏蔽器。用于替换一些敏感的值,实现BeanFactoryPostProcessor接口:
package test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionVisitor;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.util.StringValueResolver;
import java.util.HashSet;
import java.util.Set;
public class MyPostProcessor implements BeanFactoryPostProcessor {
	private Set<String> obscenties;
	public MyPostProcessor() {
		obscenties = new HashSet<>();
	}
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		String[] definitionNames = beanFactory.getBeanDefinitionNames();
		for (String beanName : definitionNames) {
			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 str = value.toString().toUpperCase();
		return this.obscenties.contains(str);
	}
	public void setObscenties(Set<String> obscenties) {
		this.obscenties.clear();
		for (String obscenty : obscenties) {
			this.obscenties.add(obscenty.toUpperCase());
		}
	}
}
text.xml文件:
<?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-3.0.xsd">
	<bean id="mybd" class="test.MyPostProcessor">
		<property name="obscenties">
			<set>
				<value>123456</value>
			</set>
		</property>
	</bean>
	<bean name="user" class="test.User">
		<!--这里的message则是个变量,最终从配置的config/bean.properties文件中读取-->
		<property name="address" value="上海"/>
		<property name="phone" value="123456"/>
	</bean>
</beans>
Test类:
@org.junit.jupiter.api.Test
void test(){
	ConfigurableListableBeanFactory bf = new XmlBeanFactory(new ClassPathResource("test.xml"));
	BeanFactoryPostProcessor mybd = (BeanFactoryPostProcessor) bf.getBean("mybd");
	mybd.postProcessBeanFactory(bf);
	User user = (User) bf.getBean("user");
	System.out.println(user.getAddress());
	System.out.println(user.getPhone());
}
@org.junit.jupiter.api.Test
void test2(){
	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
	User user = (User) context.getBean("user");
	System.out.println(user.getAddress());
	System.out.println(user.getPhone());
}
结果如下,可见Spring自动将123456这个敏感词给屏蔽掉了。
 
 至于我为什么写俩test呢,首先他们两个的效果是等价的。本篇文章主要围绕着容器ApplicationContext来展开的,那么从代码的比较上来看,我们可以发现,若是BeanFactory容器,我们需要自己手动调用postProcessBeanFactory方法,而ApplicationContext容器则自动调用了,这也是两个容器的一个区别。
1.5.3 激活处理器原理
这里我们回到invokeBeanFactoryPostProcessors(beanFactory)这行代码,来看下它的处理流程:
public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
	Set<String> processedBeans = new HashSet<>();
	// 针对BeanDefinitionRegistry进行处理
	if (beanFactory instanceof BeanDefinitionRegistry) {
		BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
		// 用于存放常规的 BeanFactoryPostProcessor
		List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
		// 存放 BeanDefinitionRegistryPostProcessor
		List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
		// 处理硬编码注册的后处理器(通过参数传进来的)
		for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
			if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
				// 因为对于BeanDefinitionRegistryPostProcessor类型,其在 BeanFactoryPostProcessor 的基础上还有自定义的方法
				BeanDefinitionRegistryPostProcessor registryProcessor =
						(BeanDefinitionRegistryPostProcessor) postProcessor;
				// 这里则进行调用
				registryProcessor.postProcessBeanDefinitionRegistry(registry);
				// 添加到registryProcessor中,为的是最后执行postProcessBeanFactory方法
				registryProcessors.add(registryProcessor);
			} else {
				// 记录常规的 BeanFactoryPostProcessor
				regularPostProcessors.add(postProcessor);
			}
		}
		// 用于保存本次要执行的BeanDefinitionRegistryPostProcessor
		List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
		// 3.调用所有实现PriorityOrdered接口的BeanDefinitionRegistryPostProcessor实现类
		// 找出所有实现BeanDefinitionRegistryPostProcessor接口的Bean的beanName
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		for (String ppName : postProcessorNames) {
			// 校验是否实现了PriorityOrdered接口
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
				// 将要被执行的加入processedBeans,避免后续重复执行
				processedBeans.add(ppName);
			}
		}
		// 排序、执行、情况
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		registryProcessors.addAll(currentRegistryProcessors);
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
		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, beanFactory.getApplicationStartup());
		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, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();
		}
		invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
	} else {
		invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
	}
	// 此时,入参中的处理器和容器中的BeanDefinitionRegistryPostProcessor已经被处理完毕
	// 接下来开始处理容器中所有的 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);
	// 其次调用 排过序 的处理器
	List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
	for (String postProcessorName : orderedPostProcessorNames) {
		orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
	}
	sortPostProcessors(orderedPostProcessors, beanFactory);
	invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
	// 最后调用 剩下 的处理器
	List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
	for (String postProcessorName : nonOrderedPostProcessorNames) {
		nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
	}
	invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
	// 清除元数据缓存
	beanFactory.clearMetadataCache();
}
代码有点冗长,这里做个宏观的总结,方便理解:
首先,我们将处理器分为两大类:
- BeanFactoryPostProcessor,本文简称- BF处理器。主要执行- postProcessBeanFactory方法。
- BeanDefinitionRegistryPostProcessor,本文简称- R处理器。主要执行- postProcessBeanDefinitionRegistry方法。
其次,先处理入参中的beanFactoryPostProcessors对象,进行分类。处理入参中的BeanFactoryPostProcessor和容器中的BeanDefinitionRegistryPostProcessor对象:
- 调用实现了PriorityOrdered接口的R处理器(具有优先级)。(包括校验操作)
- 调用实现了Ordered接口的R处理器(排过序)。
- 调用普通的R处理器。
- 调用入参中普通的BF处理器。
然后开始处理容器中所有的BF处理器,进行分类。
- 调用实现了PriorityOrdered接口的BF处理器(具有优先级)。(包括校验操作)
- 调用实现了Ordered接口的BF处理器(排过序)。
- 调用普通的BF处理器。
这里做个小区分哈,BF处理器和R处理器,都属于Spring的后置处理器,R处理器优先于BF处理器执行。 可以实现它们以达到动态注册bean定义,动态修改bean定义,以及动态修改bean。 而他们的作用也恰恰可以当做上述那一大段代码的总结。
紧接着,我们来看下registerBeanPostProcessors(beanFactory)这行代码是干什么用的。
1.5.4 注册BeanPostProcessor
首先,希望小伙伴们将BeanPostProcessor和上述的BF处理器R处理器进行区分。
- R处理器继承了- B处理器,两者都是基于- bean factory来调整上下文的- bean的属性值的。他们并不会使用- bean实例。
- BeanPostProcessor则允许动态修改应用程序上下文的- bean,这时候- bean已经实例化成功。 他的执行顺序也在最后。
我们先来看下一个简单地案例:
自定义一个后处理器,实现InstantiationAwareBeanPostProcessor接口
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		System.out.println("**************Hello World***************");
		return null;
	}
}
同时在xml文件中添加bean的配置:
<bean class="test.MyBeanPostProcessor"/>
结果如下:
 
 知道了BeanPostProcessor的一个使用之后,我们来回到代码本身,我们来看下源码:
// 注册 [拦截bean的创建过程] 的处理器
registerBeanPostProcessors(beanFactory);
↓↓↓↓↓↓
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
↓↓↓↓↓↓
public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
	// 1.查找 BeanPostProcessor 类型的 Bean 的名称集合
	String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
	/**
	 * 当Spring的配置中的后处理器还没有被注册单就已经开始了bean的初始化时
	 * 会打印出 BeanPostProcessorChecker 中设定的信息
	 * 这里则注册一个 BeanPostProcessorChecker 用于记录bean 在 beanPostProcessor 实例化时的信息
	 */
	int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
	beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
	// 2.四个集合 区分实现不同接口的 BeanPostProcessors
	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);
		}
	}
	// 3.注册实现了PriorityOrdered接口的 BeanPostProcessors
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
	// 4.注册实现了 Ordered 接口的 BeanPostProcessors
	List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
	for (String ppName : orderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		orderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	sortPostProcessors(orderedPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, orderedPostProcessors);
	// 5.注册其余常规的 BeanPostProcessors
	List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
	for (String ppName : nonOrderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		nonOrderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
	// 6.最后,注册所有 MergedBeanDefinitionPostProcessor 类型的 BeanPostProcessors
	sortPostProcessors(internalPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, internalPostProcessors);
	// 7.添加ApplicationListenerDetector探测器
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
总的来看。也就是对不同类型的BeanPostProcessor进行分类,然后分别注册。似乎和1.5.3 节没什么区别。但是还是要做好区分。
- 1.5.3 节对于BF处理器和R处理器,会调用了后处理逻辑。
- 而BeanPostProcessor的注册环节,仅仅是将其注册到BeanFactory中,并没有真正的执行!真正的执行实在bean实例化的时候发生的!
1.5.5 初始化消息资源
背景:我们的应用程序需要支持多语言。即 i18n国际化问题。
国际化信息也称为本地化信息,一般需要两个条件才可以确定一个特定类型的本地化信息:
- 语言类型。
- 国家/地区的类型。
Java则通过java.util.Locale来标识一个本地化对象,例如:
Locale locale = new Locale("zh", "CN");
同时util包下提供了几个支持本地化的格式化操作类:NumberFormat、MessageFormat等。Spring中的国际化资源操作也就是在这些类的基础上进行封装。我们先来看下MessageFormat类的使用:
@org.junit.jupiter.api.Test
void messageFormatTest() {
	String pattern1 = "{0},你好!你于{1}在银行存入{2}元";
	String pattern2 = "At {1,time,short} On{1,date,long} {0} paid {2,number,currency}";
	Object[] params = {"LJJ", new GregorianCalendar().getTime(), 1.0E3};
	
	String s = MessageFormat.format(pattern1, params);
	System.out.println(s);
	MessageFormat mf = new MessageFormat(pattern2, Locale.US);
	String s2 = mf.format(params);
	System.out.println(s2);
}
结果如下:
 
 Spring中则定义了访问国际化信息的MessageSource接口。我们来看下refresh()源码中的第七步:为上下文初始化Message,国际化处理。
initMessageSource();
protected void initMessageSource() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	// bean的名称额必须是messageSource
	if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
		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) {
				// // 如果已经注册的父上下文没有消息源,则只能将父上下文设置为父消息源
				hms.setParentMessageSource(getInternalParentMessageSource());
			}
		}
		if (logger.isTraceEnabled()) {
			logger.trace("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.isTraceEnabled()) {
			logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
		}
	}
}
这段代码很简单:
- 将实现了MessageSource接口的bean存放在ApplicationContext的成员变量中。
- 先看是否有此配置,如果有就实例化。
- 否则就创建一个DelegatingMessageSource实例的bean。
那源码中出现的HierarchicalMessageSource类是干啥的呢?它是MessageSource接口的一个扩展接口。而其有个重要的实现类为ResourceBundleMessageSource类,我们来看下其使用:
1.创建国际化配置文件:
 
 2.创建一个名字为message的文件:选中左侧的英语,然后点下→按钮
 
 此时会自动生成两种文件:
 
 test.xml配置文件如下:
<bean id="messageSource"
	 class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
	<property name="defaultEncoding" value="UTF-8" />
	<property name="basenames">
		<list>
			<value>test/message</value>
		</list>
	</property>
</bean>
Test类:
@org.junit.jupiter.api.Test
void messageFormatTest2() {
	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
	String str1 = context.getMessage("test", null, Locale.ENGLISH);
	String str2 = context.getMessage("test", null, Locale.CHINA);
	System.out.println(str1);
	System.out.println(str2);
}
结果如下:
 
 将这个小案例和上述源码结合起来看也就是:
- 若我们配置了国际化资源文件,并且存在实现了MessageSource接口的bean。
- 那么ApplicationContext会将其整合到容器里面。
- 那么此时我们调用getMessage()方法,也就是调用对应子类的实现而已。
1.5.6 初始化消息广播器
首先我们来看下Spring中监听器的使用:
1.定义监听事件:
public class MyEvent extends ApplicationEvent {
	public String msg;
	public MyEvent(Object source) {
		super(source);
	}
	public MyEvent(Object source, String msg) {
		super(source);
		this.msg = msg;
	}
	public void print() {
		System.out.println(msg);
	}
}
2.定义监听器:
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
public class MyListener implements ApplicationListener {
	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof MyEvent) {
			MyEvent myEvent = (MyEvent) event;
			((MyEvent) event).print();
		}
	}
}
3.test.xml文件:
<?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-3.0.xsd">
	<bean id="myListener" class="test.listener.MyListener"/>
</beans>
4.Test方法:
@org.junit.jupiter.api.Test
void test() {
	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("listener/test.xml");
	MyEvent myEvent = new MyEvent("hello", "你好,上海");
	context.publishEvent(myEvent);
}
结果如下:
 
 我们发现,程序运行的时候,Spring会将发出的MyEvent事件转给我们自定义的监听器MyListener处理(观察者模式)。
1.6 初始化非延迟加载单例
这一环节我们主要围绕finishBeanFactoryInitialization这个方法来展开。其主要做完成BeanFactory的初始化工作,其中包括conversionService的设置、配置冻结和非延迟加载单例的初始化工作:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// 1.初始化此上下文的转换服务,完成conversionService的设置
	if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
			beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
		beanFactory.setConversionService(
				beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
	}
	// 如果beanFactory之前没有注册嵌入值解析器,则注册默认的嵌入值解析器:主要用于注解属性值的解析。
	if (!beanFactory.hasEmbeddedValueResolver()) {
		beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
	}
	// 初始化LoadTimeWeaverAware Bean实例对象
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
	for (String weaverAwareName : weaverAwareNames) {
		getBean(weaverAwareName);
	}
	// Stop using the temporary ClassLoader for type matching.
	beanFactory.setTempClassLoader(null);
	// 2.冻结所有的bean定义,说明此时注册的bean定义 将不能够被修改。此时马上要创建bean实例对象了
	beanFactory.freezeConfiguration();
	// 3.初始化剩下的单例bean
	beanFactory.preInstantiateSingletons();
}
先来看下第一步,我们来熟悉下ConversionService是干什么的:
@org.junit.jupiter.api.Test
void test3() {
	DefaultConversionService conversionService = new DefaultConversionService();
	double d = conversionService.convert("1.2", double.class);
	System.out.println(d); 
	int i = conversionService.convert("2", int.class);
	System.out.println(i);
	Byte b = conversionService.convert("0x10", Byte.class);
	System.out.println(Integer.toBinaryString(b));
}
结果如下:
 
 第二步冻结所有的bean定义,无非就是将beanDefinitionNames集合转化为String数组,本身没什么好探索的。我们直接来看第三步,非延迟bean 的加载。
- 懒加载:用的时候才加载构造,不用的时候不加载。
- 非懒加载(非延迟):容器启动的时候立刻创建对象。
接下来看下preInstantiateSingletons的源码:
@Override
public void preInstantiateSingletons() throws BeansException {
	if (logger.isTraceEnabled()) {
		logger.trace("Pre-instantiating singletons in " + this);
	}
	// 1.将所有BeanDefinition的名字创建一个集合
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
	// 2.触发所有 非延迟加载单例bean的初始化
	for (String beanName : beanNames) {
		// 3.合并父类BeanDefinition
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		// 4.条件判断:抽象、单例、非懒加载
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			// 是否实现了FactoryBean接口
			if (isFactoryBean(beanName)) {
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				// 类型转换
				if (bean instanceof FactoryBean) {
					FactoryBean<?> factory = (FactoryBean<?>) bean;
					// 判断该FactoryBean是否希望立即初始化
					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);
			}
		}
	}
	// 遍历beanNames,触发所有SmartInitializingSingleton的后初始化回调
	// 当所有单例 bean 都初始化完成以后,会执行afterSingletonsInstantiated()方法
	for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName);
		// 判断singletonInstance是否实现了SmartInitializingSingleton接口
		if (singletonInstance instanceof SmartInitializingSingleton) {
			StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
					.tag("beanName", beanName);
			SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
			if (System.getSecurityManager() != null) {
				AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
					smartSingleton.afterSingletonsInstantiated();
					return null;
				}, getAccessControlContext());
			}
			else {
				smartSingleton.afterSingletonsInstantiated();
			}
			smartInitialize.end();
		}
	}
}
总结下本方法主要做了这么几件事:
- 准备转换器ConversionService。其作用也就是bean的一个属性解析。
- 然后在初始化bean之前,把这些bean冻结起来,不让他们被修改。
- 然后对于那些希望在容器启动阶段就创建的bean(非延迟),调用getBean()方法创建。(其详细过程:Spring源码系列:Bean的加载)
1.7 完成上下文的刷新工作
终于来到了refresh()方法的最后一步:finishRefresh
protected void finishRefresh() {
	// 1.清理缓存
	clearResourceCaches();
	// 2.为此上下文初始化生命周期处理器,它有啥作用呢?
	// ApplicationContext容器在启动或者停止的时候,需要LifecycleProcessor来和所有的bean的生命周期做状态更新
	initLifecycleProcessor();
	// 3.将刷新完毕事件传播到生命周期处理器。启动所有实现了Lifecycle接口的bean
	getLifecycleProcessor().onRefresh();
	// 4.推送上下文刷新完毕事件到相应的监听器
	publishEvent(new ContextRefreshedEvent(this));
	if (!NativeDetector.inNativeImage()) {
		LiveBeansView.registerApplicationContext(this);
	}
}
二. 总结
ApplicationContext容器在传统的BeanFactory容器上扩展了很多功能,而这些功能的扩展都靠refresh()方法的调用,而该方法又拓展了这么几个主要的功能:
1.环境准备。
- 比如我们可以校验该程序是否在特定的环境变量下运行的。
2.加载BeanFactory。
- 进行功能的拓展,用户可自定义属性,是否允许覆盖名称的不同定义的对象以及bean之间发生发生循环依赖。
- 加载BeanDefinition。(做和BeanFactory一样的事情)
3.填充BeanFactory,增加一些功能支持:
- 增加对SpEL语言的支持。
- 增加对属性编辑器的支持。(例如支持String类型的属性转Date)
- 让一些实现了Aware接口的bean,在初始化的时候能够获得对应的资源,如添加当前容器的系统环境相关属性
- 增加AspectJ的支持
4.BeanFactory的后处理:
- 按顺序调用BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry()。
- BeanFactoryPostProcessor.postProcessBeanFactory()。 可以实现它们以达到动态注册- bean定义,动态修改- bean定义,以及动态修改- bean。
- 激活BeanPostProcessor处理器。
- 初始化各种实现了MessageSource接口的子类。完成消息和资源的初始化。例如国际化i18n配置。
- 初始化消息广播器。
5.初始化非延迟加载单例:
- 准备转换器ConversionService。其作用也就是bean的一个属性解析。
- 然后在初始化bean之前,把这些bean冻结起来,不让他们被修改。
- 然后对于那些希望在容器启动阶段就创建的bean(非延迟),调用getBean()方法创建。(其详细过程:Spring源码系列:Bean的加载)
6.完成上下文的刷新工作。
最后,我们可以看出来,ApplicationContext和BeanFactory的一个优缺点比较:
-  功能的丰富程度上, ApplicationContext拓展的功能更多,使用率也更高。
-  但是功能多了,启动过程复杂了,那么 ApplicationContext的启动速度必然要比BeanFactory要慢。
下一篇文章准备学习下Spring-AOP,也正好弥补本文当中ApplicationContext容器对AspectJ功能支持 这一环节源码的讲解。










