Spring源码系列 - 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功能支持 这一环节源码的讲解。