这篇文章主要介绍了Spring5源码之ApplicationContext的接口,用于加载bean,详细分析了初始化和刷新的过程。需要的朋友可以参考一下。
1、ClassPathXmlApplicationContext源码解析
独立的XML应用程序上下文,获取上下文定义文件,从类路径中将普通路径解释为类路径资源名。
/**
* Standalone XML application context, taking the context definition files
* from the class path, interpreting plain paths as class path resource names
* that include the package path (e.g. "mypackage/myresource.txt"). Useful for
* test harnesses as well as for application contexts embedded within JARs.
*
* <p>The config location defaults can be overridden via {@link #getConfigLocations},
* Config locations can either denote concrete files like "/myfiles/context.xml"
* or Ant-style patterns like "/myfiles/*-context.xml" (see the
* {@link org.springframework.util.AntPathMatcher} javadoc for pattern details).
*
* <p>Note: In case of multiple config locations, later bean definitions will
* override ones defined in earlier loaded files. This can be leveraged to
* deliberately override certain bean definitions via an extra XML file.
*
* <p><b>This is a simple, one-stop shop convenience ApplicationContext.
* Consider using the {@link GenericApplicationContext} class in combination
* with an {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}
* for more flexible context setup.</b>
*
* @author Rod Johnson
* @author Juergen Hoeller
* @see #getResource
* @see #getResourceByPath
* @see GenericApplicationContext
*/
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
2、ClassPathXmlApplicationContext构造器
使用给定的父类创建一个新的ClassPathXmlApplicationContext,从给定的XML文件中加载定义。
/**
* Create a new ClassPathXmlApplicationContext with the given parent,
* loading the definitions from the given XML files.
* @param configLocations array of resource locations
* @param refresh whether to automatically refresh the context,
* loading all bean definitions and creating all singletons.
* Alternatively, call refresh manually after further configuring the context.
* @param parent the parent context
* @throws BeansException if context creation failed
* @see #refresh()
*/
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
// 设置配置路径
setConfigLocations(configLocations);
// 是否自动刷新上下文
if (refresh) {
// 解析和功能实现方法
refresh();
}
}
3、设置路径setConfigLocations
此方法主要用于解析给定的路径数组,当然,如果数组中包含特殊字符,如${var},那么resolvePath方法中会搜索寻找匹配的系统变量并进行替换。
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;
}
}
4、扩展功能refresh
refresh方法中包含了几乎ApplicationContext中提供的全部功能,而且此方法中逻辑非常清晰明了,使得我们很容易分析对应的层级和逻辑功能。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1 准备刷新上下文
prepareRefresh();
// 2 初始化BeanFactory,并进行XML文件读取
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3 对BeanFactory进行各种功能的填充
prepareBeanFactory(beanFactory);
try {
// 4 子类覆盖方法做额外的处理
postProcessBeanFactory(beanFactory);
// 5 激活各种BeanFactory的处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 6 注册拦截Bean创建Bean处理器,这里只是注册,真正的调用时在getBean时候
registerBeanPostProcessors(beanFactory);
// 7 为上下文初始化Message源,即不同语言的消息体,国际化处理
initMessageSource();
// 8 初始化应用消息广播器,并放入"applicationEventMulticaster"bean中
initApplicationEventMulticaster();
// 9 留给子类来初始化其他的Bean
onRefresh();
// 10 在所有注册的bean中查找Listen beans,注册到消息广播中
registerListeners();
// 11 初始化剩下的单实例(非惰性的)
finishBeanFactoryInitialization(beanFactory);
// 12 最后一步:完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshedEvent通知
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 1 销毁已经创建的单例,以避免挂起资源。
destroyBeans();
// 2 重新设置active标志
cancelRefresh(ex);
// 3 将异常传播给调用者
throw ex;
}
finally {
// 4 重置Spring核心的普通内省缓存,因为我们可能再也不需要单例bean的元数据了
resetCommonCaches();
}
}
}
5、ClassPathXmlApplicationContext初始化步骤
- 1 初始化前的准备工作,例如对系统属性或者环境变量进行准备及验证。
在某种情况下项目使用需要读取某些系统变量,而这个变量的设置可能会影响系统的正确性,那么ClassPathXmlApplicationContext为我们提供的这个准备函数就显得非常必要,它可以在Spring启动的时候提前对必需的变量进行存在性验证。 - 2 初始化BeanFactory,并进行XML文件读取。
之前有提到ClassPathXmlApplicationContext包含着BeanFactory所提供的一切特征,那么在这一步骤中将会复用BeanFactory中的配置文件读取解析其他功能,这一步之后ClassPathXmlApplicationContext实际上就已经包含了BeanFactory所提供的功能,也就是可以进行bean的提取等操作了。 - 3 对BeanFactory进行各种功能填充
@Qualifier与@Autowired应该是大家非常熟悉的注解,那么这两个注解正是在一步骤中增加支持。 - 4 子类覆盖方法做额外的处理
Spring之所以强大,为世人所推崇,除了它能上为大家提供了便利外,还有一方面是它的完美架构,开放式的架构让使用它的程序员很容易根据业务需要扩展已经存在的功能。这种开放式的设计在Spring中随处可见,例如本例中就提供了一个空的函数实现postProcessBeanFactory(模板方法)来方便程序员在业务上做进一步的扩展。 - 5 激活各种BeanFactory的处理器。
- 6 注册拦截Bean创建Bean处理器,这里只是注册,真正的调用时在getBean时候。
- 7 为上下文初始化Message源,即不同语言的消息体,国际化处理。
- 8 初始化应用消息广播器,并放入"applicationEventMulticaster"bean中。
- 9 留给子类来初始化其他的Bean。
- 10 在所有注册的bean中查找Listen beans,注册到消息广播中。
- 11 初始化剩下的单实例(非惰性的)。
- 12 最后一步:完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshedEvent通知。
6、环境准备prepareRefresh源码解析
prepareRefresh方法主要是做些准备工作,例如对系统属性及环境变量的初始化及验证。
/**
* 为刷新准备这个上下文,设置它的启动日期和活动标志,并执行任何初始化的属性
*/
protected void prepareRefresh() {
// 1 切换到活跃
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// 2 留给子类覆盖
initPropertySources();
// 3 验证需要的属性文件是否都已经放入环境中
getEnvironment().validateRequiredProperties();
// 4 存储早期应用监听器ApplicationListeners
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// 5 重置早期应用监听器ApplicationListeners
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// 6 允许收集早期的ApplicationEvents,一旦事件中的助手类可用,就会发布
this.earlyApplicationEvents = new LinkedHashSet<>();
}
- initPropertySources扩展
initPropertySources正符合Spring的开放式结构设计,给用户最大扩展Spring的能力。用户可以根据自身的需要重写initPropertySources方法,并在方法中进行个性化的属性处理及设置。 - initPropertySources使用案例
普通的bean:MyTestBean
package com.test.bean;
public class MyTestBean {
private String testStr = "testStr";
public String getTestStr() {
return testStr;
}
public void setTestStr(String testStr) {
this.testStr = testStr;
}
}
自定义的ClassPathXmlApplicationContext:MyClassPathXmlApplicationContext
package com.test.application;
import org.springframework.beans.BeansException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Description: 自定义ClassPathXmlApplicationContext
* @Author: Janson
* @Date: 2020/4/12 12:32
**/
public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
public MyClassPathXmlApplicationContext(String... configLocations) throws BeansException {
super(configLocations);
}
@Override
protected void initPropertySources() {
getEnvironment().setRequiredProperties("myProperties");
}
}
resources目录下的资源文件application.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.xsd">
<bean id="myTestBean" class="com.test.bean.MyTestBean"></bean>
</beans>
ClassPathXmlApplicationContext测试类:MyClassPathXmlApplicationContextTest
package com.test;
import com.test.application.MyClassPathXmlApplicationContext;
import com.test.bean.MyTestBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
/**
* @Description: MyClassPathXmlApplicationContext测试类
* @Author: Janson
* @Date: 2020/4/12 15:04
**/
@Slf4j
public class MyClassPathXmlApplicationContextTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new MyClassPathXmlApplicationContext("application.xml");
MyTestBean myTestBean = (MyTestBean) applicationContext.getBean("myTestBean");
log.info("testStr:{}", myTestBean.getTestStr());
}
}
测试类输出结果
- 不加环境变量myProperties,控制台输出结果
16:28:46.864 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Could not find key 'myProperties' in any property source
Exception in thread "main" org.springframework.core.env.MissingRequiredPropertiesException: The following properties were declared as required but could not be resolved: [myProperties]
- 加环境变量myProperties,控制台输出结果及添加环境变量如下图所示
16:21:25.511 [main] INFO com.test.MyClassPathXmlApplicationContextTest - testStr:testStr
7、加载BeanFactory源码解析
obtainFreshBeanFactory方法从字面理解就是获取BeanFactory。之前有说过,ApplicationContext是对BeanFactory的功能上的扩展,不但包含了BeanFactory的全部功能,更在其基础上添加了大量的扩展应用,那么obtainFreshBeanFactory正是实现BeanFactory的地方,也就是经过这个函数后ApplicationContext就已经拥有了BeanFactory的全部功能。
- obtainFreshBeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 初始化BeanFactory,并进行XML文件读取,并将得到的BeanFactory记录在当前实体的属性中
refreshBeanFactory();
// 返回当前实体的beanFactory属性
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
- 方法中核心实现委托给refreshBeanFactory
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 1 创建DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 2 为了序列化指定id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象
beanFactory.setSerializationId(getId());
// 3 定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖
customizeBeanFactory(beanFactory);
// 4 初始化DocumentReader,并进行XML文件读取及解析
loadBeanDefinitions(beanFactory);
// 5 使用全局变量记录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 beanFactory = new XmlBeanFactory(new ClassPathResource("application.xml"));
其中XmlBeanFactory继承自DefaultListableBeanFactory并提供了
XmlBeanDefinitionReader类型的reader属性,也就是说DefaultListableBeanFactory是容器的为基础。必须先实例化,那么在这里就是实例化DefaultListableBeanFactory的步骤。
2、指定序列化ID。
3、定制BeanFactory。
4、加载BeanDefinition。
5、使用全局变量记录BeanFactory类实例。
因为DefaultListableBeanFactory类型的变量beanFactory是函数内的局部变量,所以使用全部变量记录解析结果。
定制BeanFactory
- customizeBeanFactory方法
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);
}
}
- 自定义MyClassPathXmlApplicationContext(采用子类覆盖方法)
public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
@Override
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
super.setAllowBeanDefinitionOverriding(false);
super.setAllowCircularReferences(false);
super.customizeBeanFactory(beanFactory);
}
- 解析器AutowireCandidateResolver
解析autowire类型时会首先调用的方法:
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
- QualifierAnnotationAutowireCandidateResolver解析器的getSuggestedValue方法
/**
- 确定给定的依赖项是否声明了值注释
*/
@Override
@Nullable
public Object getSuggestedValue(DependencyDescriptor descriptor) {
// 从任何给定的候选注释中确定建议值
Object value = findValue(descriptor.getAnnotations());
if (value == null) {
// 如果有的话,返回包装好的MethodParameter
MethodParameter methodParam = descriptor.getMethodParameter();
if (methodParam != null) {
// 返回与目标方法/构造函数本身相关联的注解。
value = findValue(methodParam.getMethodAnnotations());
}
}
return value;
}
加载BeanDefinition
- loadBeanDefinitions
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 为指定的beanFactory创建XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 对beanDefinitionReader进行环境变量设置
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 对beanDefinitionReader进行环境变量设置进行设置,可以覆盖
initBeanDefinitionReader(beanDefinitionReader);
// 使用给定的XmlBeanDefinitionReader加载bean定义
loadBeanDefinitions(beanDefinitionReader);
}
使用XmlBeanDefinitionReader的loadBeanDefinitions方法进行配置文件的加载注册相信大家已经不陌生了,这完全就是开始BeanFactory的套路。因为在XmlBeanDefinitionReader中已经将之前初始化的DefaultListableBeanFactory注册进去了,所以XmlBeanDefinitionReader所读取的BeanDefinitionHolder都会注册到DefaultListableBeanFactory中,也就是经过此步骤,类型DefaultListableBeanFactory的变量beanFactory已经包含了所有解析好的配置。
8、功能扩展prepareBeanFactory源码解析
- prepareBeanFactory方法源码
在进入prepareBeanFactory方法之前,spring已经完成了对配置的解析,而ApplicationContext在功能上的扩展也由此展开。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 1 设置beanFactory的classLoader为当前context的classLoader
beanFactory.setBeanClassLoader(getClassLoader());
// 2 设置beanFactory的表达式语言处理器,Spring3增加了表达式语言的支持。
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 3 为beanFactory增加了一个默认的propertyEditor,这个主要是对bean的属性设置管理的一个工具
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
//4 添加一个新的BeanPostProcessor,它将被应用到这个工厂创建的bean中
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 5 设置了几个忽略自动装配的接口
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// 6 设置了几个自动装配的特殊规则
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 7 将早期用于检测内部bean的后处理器注册为ApplicationListenerDetector
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// 8 增加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()));
}
// 9 添加默认的系统环境beans
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());
}
}
- 属性注册编辑器案例
UserManager类
package com.test.bean;
import lombok.Data;
import java.util.Date;
/**
* @Description: user manager
* @Author: Janson
* @Date: 2020/4/13 23:16
**/
@Data
public class UserManager {
private Date dateValue;
}
resources目录下的bean.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.xsd">
<bean id="userManager" class="com.test.bean.UserManager">
<property name="dateValue" value="2020-04-13"></property>
</bean>
</beans>
属性编辑器测试类
package com.test;
import com.test.bean.UserManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Description: propertyEditor测试类
* @Author: Janson
* @Date: 2020/4/13 23:44
**/
@Slf4j
public class PropertyEditorTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
UserManager userManager = (UserManager) applicationContext.getBean("userManager");
log.info("dateValue:{}", userManager.getDateValue());
}
}
测试类输出结果
Caused by: java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Date' for property 'dateValue': no matching editors or conversion strategy found
结论:这样使用会直接抛出如上异常,类型转换不成功。因为UserManager中的dataValue的属性是Date类型的,而XML中配置的却是String类型的,所以当然会报异常。
Spring针对此问题提供了解决办法
定义属性编辑器DatePropertyEditorRegistrar
package com.test.support;
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @Description: Date PropertyEditorRegistrar
* @Author: Janson
* @Date: 2020/4/14 22:49
**/
public class DatePropertyEditorRegistrar implements PropertyEditorRegistrar {
@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Date.class,new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
}
}
注册到Spring中
<!--注册Spring自带编辑器-->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="com.test.support.DatePropertyEditorRegistrar"></bean>
</list>
</property>
</bean>
启动测试类,输出结果如下:
22:55:53.383 [main] INFO com.test.PropertyEditorTest - dateValue:Mon Apr 13 00:00:00 CST 2020
- 注册默认编辑器doRegisterEditor
/**
- 如果可能的话,覆盖默认编辑器(因为这是我们在这里真正想做的);否则注册为自定义编辑器。
*/
private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
if (registry instanceof PropertyEditorRegistrySupport) {
((PropertyEditorRegistrySupport) registry).overrideDefaultEditor(requiredType, editor);
}
else {
registry.registerCustomEditor(requiredType, editor);
}
}
- ApplicationContextAwareProcessor处理器
对于postProcessAfterInitialization方法,在ApplicationContextAwareProcessor没有做过多的逻辑处理,重点看一下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>) () -> {
// 调用aware相关接口获取资源
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
// 调用aware相关接口获取资源
invokeAwareInterfaces(bean);
}
return bean;
}
invokeAwareInterfaces方法
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在被初始化之后,可以取得一些对应的资源。
- 设置忽略依赖
当Spring将ApplicationContextAwareProcessor注册后,那么在invokeAwareInterfaces方法中间调用的Aware类已经不是普通的bean了,如ResourceLoaderAware、ApplicationEventPublisherAware、ApplicationContextAware等,那么当然需要在Spring做bean的依赖注入的时候忽略他们,而ignoreDependencyInterface的作用正是在此。
// 5 设置了几个忽略自动装配的接口
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
- 注册依赖
Spring中有了忽略依赖的功能,当然也必不可少地会有注册依赖功能。
当注册了依赖解析后,例如当注册了对BeanFactory.class的解析依赖后,当bean的属性注入的时候,一旦检测到属性为BeanFactory类型便会将beanFactory的实例注入进去。
// 6 设置了几个自动装配的特殊规则
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
9、 模板方法postProcessBeanFactory
子类覆盖方法做额外的处理
// 子类覆盖方法做额外的处理
postProcessBeanFactory(beanFactory);
10、激活的BeanFactoryPostProcessor
在正式介绍之前,我们先了解下BeanFactoryPostProcessor的用法。
BeanFactoryPostProcessor接口和BeanPostProcessor类似,可以对bean的定义(配置元数据)进行处理。也就是说,Spring的IOC容器允许BeanFactoryPostProcessor在容器实际实例化任何其他的bean之前读取配置元数据,并有可能修改它。如果你愿意,你可以配置多个BeanFactoryPostProcessor并可以通过order属性(需要实现Ordered接口)来控制BeanFactoryPostProcessor的执行顺序。如果你想改变实际的bean实例(例如从配置元数据创建的对象),那么你们最好使用BeanPostProcessor。同样地,BeanFactoryPostProcessor的作用域范围是容器级的。它只和你所使用的容器有关。如果你在容器中定义一个BeanFactoryPostProcessor不会对定义在另一个容器中的bean进行后置处理,即使这两个容器都是在同一个层级上。在Spring中存在对于BeanFactoryPostProcessor的典型应用,比如PropertyPlaceholderConfigurer。
- 自定义BeanFactoryPostProcessor案例
我们实现一个 BeanFactoryPostProcessor,去除敏感属性值的功能来展示自定义的BeanFactoryPostProcessor的创建及使用。
配置文件beanFactory.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.xsd">
<bean id="customBeanFactoryPostProcessor" class="com.test.factory.CustomBeanFactoryPostProcessor">
<property name="sensitives">
<set>
<value>bollocks</value>
<value>inky</value>
<value>bum</value>
<value>Microsoft</value>
</set>
</property>
</bean>
<bean id="simpleBean" class="com.test.factory.SimplePostProcessor">
<property name="connectionString" value="bollocks"></property>
<property name="username" value="Microsoft"></property>
<property name="password" value="imaginecup"></property>
</bean>
</beans>
自定义CustomBeanFactoryPostProcessor
package com.test.factory;
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;
/**
* @Description: Custom BeanFactoryPostProcessor
* @Author: Janson
* @Date: 2020/4/16 22:50
**/
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private Set<String> sensitives;
public CustomBeanFactoryPostProcessor() {
this.sensitives = new HashSet<>();
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
StringValueResolver valueResolver = new StringValueResolver() {
@Override
public String resolveStringValue(String strVal) {
if (isSensitive(strVal)) {
return "******";
}
return strVal;
}
};
BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
visitor.visitBeanDefinition(bd);
}
}
private boolean isSensitive(Object value) {
if (value != null) {
String upValue = value.toString().toUpperCase();
return this.sensitives.contains(upValue);
}
return false;
}
public void setSensitives(Set<String> sensitives) {
this.sensitives.clear();
for (String sensitive : sensitives) {
this.sensitives.add(sensitive.toUpperCase());
}
}
}
普通的bean:SimplePostProcessor
package com.test.factory;
import lombok.Data;
/**
* @Description: SimplePostProcessor
* @Author: Janson
* @Date: 2020/4/16 23:15
**/
@Data
public class SimplePostProcessor {
private String connectionString;
private String username;
private String password;
}
测试类BeanFactoryPostProcessorTest
package com.test;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
/**
* @Description: BeanFactoryPostProcessor测试类
* @Author: Janson
* @Date: 2020/4/16 23:09
**/
@Slf4j
public class BeanFactoryPostProcessorTest {
public static void main(String[] args) {
Resource resource = new ClassPathResource("beanFactory.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader((BeanDefinitionRegistry) factory);
beanDefinitionReader.loadBeanDefinitions(resource);
BeanFactoryPostProcessor bfpp = (BeanFactoryPostProcessor) factory.getBean("customBeanFactoryPostProcessor");
bfpp.postProcessBeanFactory(factory);
Object simpleBean = factory.getBean("simpleBean");
log.info("simpleBean:{}", simpleBean);
}
}
测试输出结果
10:59:23.157 [main] INFO com.test.BeanFactoryPostProcessorTest - simpleBean:SimplePostProcessor(connectionString=******, username=imaginecup, password=******)
- BeanFactoryPostProcessor源码解析
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// 对BeanDefinitionRegistryPostProcessors类型的处理
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
// 定义扩展类BeanFactoryPostProcessor的BeanDefinitionRegistryPostProcessor集合
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// 硬编码注册的后处理器
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
// 对于BeanDefinitionRegistryPostProcessor类型,在BeanFactoryPostProcessor的基础上还有自己定义的方法,需要先调用。
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
// 记录常规的BeanFactoryPostProcessor集合
regularPostProcessors.add(postProcessor);
}
}
// 不要在这里初始化factorybean:我们需要保留所有常规bean,未初始化,让bean工厂的后置处理器应用于它们!
// 将实现的beandefinitionregistrypostprocessor分开优先顺序,顺序,等等。
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// 首先,调用实现PriorityOrdered的BeanDefinitionRegistryPostProcessors
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的BeanDefinitionRegistryPostProcessors
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();
// 最后,调用所有其他的BeanDefinitionRegistryPostProcessors,直到没有其他的出现。
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();
}
// 现在,调用到目前为止处理的所有处理器的postProcessBeanFactory回调。
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// 调用用上下文实例注册的工厂处理器
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// 不要在这里初始化FactoryBeans:我们需要保留所有常规bean,未初始化,以让bean工厂的后处理器应用于它们!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// 在实现PriorityOrdered、Ordered和其他的BeanFactoryPostProcessors之间进行分离,
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// 跳过-已经在第一阶段处理了
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 首先,调用实现PriorityOrdered.的BeanFactoryPostProcessors
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 接下来,调用实现Ordered的BeanFactoryPostProcessors
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// 最后,调用所有其他BeanFactoryPostProcessors
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// 清除缓存的合并bean定义,因为后处理器可能有修改了原始的元数据,例如替换了值中的占位符…
beanFactory.clearMetadataCache();
}
从上面的源码解析可以看到,对于BeanFactoryPostProcessor的处理主要分两种情况进行,一个是对于BeanDefinitionRegistry类的特殊处理,另一种是对普通的BeanFactoryPostProcessor进行处理。
- 注册BeanPostProcessor案例
Spring中大部分功能都是通过后处理器的方式进行扩展的,这是Spring框架的一个特性,但是在BeanFactory中其实并没有实现后处理器的自定注册,所以在调用的时候如果没有进行手动注册其实是不能使用的。但是在ApplicationContext中增加自动注册功能。
自定义后处理器CustomInstantiationAwareBeanPostProcessor
package com.test.processor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
/**
* @Description: Custom InstantiationAwareBeanPostProcessor
* @Author: Janson
* @Date: 2020/4/18 12:29
**/
@Slf4j
public class CustomInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
log.info("postProcessBeforeInstantiation:====");
return null;
}
}
bean.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.xsd">
<bean id="dog" class="com.test.bean.Dog">
<property name="name" value="Hello Dog"></property>
<property name="age" value="1"></property>
</bean>
<bean id="customInstantiationAwareBeanPostProcessor" class="com.test.processor.CustomInstantiationAwareBeanPostProcessor"></bean>
</beans>
普通的bean:Dog
package com.test.bean;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@Data
@Slf4j
public class Dog {
private String name;
private Integer age;
public void print() {
log.info("dog name:{} age:{}", name, age);
}
}
测试类BeanPostProcessorTest
package com.test;
import com.test.bean.Dog;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Description: BeanPostProcessor测试类
* @Author: Janson
* @Date: 2020/4/6 15:40
**/
public class BeanPostProcessorTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
Dog dog = (Dog) applicationContext.getBean("dog");
}
}
输出结果
21:14:53.930 [main] INFO com.test.processor.CustomInstantiationAwareBeanPostProcessor - postProcessBeforeInstantiation:====
11、注册的BeanPostProcessor
- 注册的BeanPostProcessor的源码分析
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);
}
}
// 第1步,注册所有实现PriorityOrdered的BeanPostProcessors
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// 第2步,注册所有实现Ordered的BeanPostProcessors
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);
//第3步,注册所有无序的BeanPostProcessors
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);
// 第4步,注册所有内部BeanPostProcessors
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// 第5步,将检测内部bean的后处理器重新注册为ApplicationListenerDetector,将它移动到处理器链的末端(用于获取代理等)
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
- 注册的BeanPostProcessor的源码分析总结说明
从以上源码分析和注释,我们做一下总结。首先我们会发现,对于BeanPostProcessor的处理与BeanFactoryPostProcessor的处理极为相似,但是似乎有有些不一样的地方。经过反复的对比发现,对于BeanFactoryPostProcessor的处理区分两种情况,一种方式是通过硬编码的方式的处理,另外一种是通过配置文件的处理。那么为什么在BeanPostProcessor的处理中只考虑了配置文件的方式而不考虑硬编码的方式呢?提出这个问题,还是因为读者没有完全理解两者实现的功能。对于BeanFactoryPostProcessor的处理,不但要实现注册功能,而且还要实现对后处理的激活操作,所以需要载入配置中的定义并进行激活;而对于BeanPostProcessor并不需要马上调用,再说,硬编码的方式实现的功能是将后处理器提起并调用,这里不需要调用,当然不需要考虑硬编码的方式了,这里的功能只需要将配置文件的BeanPostProcessor提出出来并注入beanFactory就可以了。
对于beanFactory的注册,也不是直接注册就可以的。在Spring中支持对于BeanPostProcessor的排序,比如根据PriorityOrdered进行排序、根据Ordered进行排序或者无序,而Spring在BeanPostProcessor的激活顺序的时候也会考虑对于顺序的问题而先进行排序。
12、初始化消息资源
“国际化信息”也被称为“本地化信息”,一般需要两个条件才可以确定一个特定类型的本地化信息,它们分别是“语言类型”和“国家/地区的类型”。
-
国际信息化接口MessageSource
ResourceBundleMessageSource和ReloadableResourceBundleMessageSource与HierarchicalMessageSource的依赖关系如下图所示:
ResourceBundleMessageSource
ReloadableResourceBundleMessageSource
HierarchicalMessageSource接口最重要的两个实现类是ResourceBundleMessageSource和ReloadableResourceBundleMessageSource。它们是基于Java的ResourceBundle基础类实现的,允许通过资源名加载国际化资源。ReloadableResourceBundleMessageSource提供了定时顺序功能,允许在不重启系统的情况下,更新资源的信息。StaticMessageSource主要用于程序测试,他允许听你刚刚编程的方式提供国际化信息。而DelegatingMessageSource是为方便操作父类MessageSource而提供的代理类。 -
initMessageSource源码解析
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);
// 让MessageSource知道父消息源
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// 如果没有父消息源,则只将父上下文设置为父消息源注册了。 hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isDebugEnabled()) {
logger.debug("Using MessageSource [" + this.messageSource + "]");
}
}
else {
// 使用空的MessageSource来接受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);
}
其中getMessageSoure()方法正是获取了之前定义的自定义资源配置。
13、初始化ApplicationEventMulticaster
在讲解Spring的时间传播器之前,我们还是先来看一下Spring的事件监听的简单用法。
- Spring事件监听的案例
定义监听事件MyEvent
package com.test.event;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEvent;
import java.io.Serializable;
/**
* @Description: 定义监听事件
* @Author: Janson
* @Date: 2020/4/19 9:32
**/
@Slf4j
public class MyEvent extends ApplicationEvent implements Serializable {
private static final long serialVersionUID = -2846915828284386885L;
private String msg;
/**
* Create a new ApplicationEvent.
*
* @param source the object on which the event initially occurred (never {@code null})
*/
public MyEvent(Object source) {
super(source);
}
public MyEvent(Object source, String msg) {
super(source);
this.msg = msg;
}
public void print() {
log.info("msg:{}", msg);
}
}
定义监听器MyListener
package com.test.listener;
import com.test.event.MyEvent;
import org.springframework.context.ApplicationListener;
/**
* @Description: 定义监听器
* @Author: Janson
* @Date: 2020/4/19 9:36
**/
public class MyListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
event.print();
}
}
配置资源文件event.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.xsd">
<bean id="myListener" class="com.test.listener.MyListener"></bean>
</beans>
事件测试类MyEventTest
package com.test;
import com.test.event.MyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Description: 事件测试类
* @Author: Janson
* @Date: 2020/4/19 9:41
**/
public class MyEventTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:event.xml");
MyEvent myEvent = new MyEvent("hello", "this is a event msg");
applicationContext.publishEvent(myEvent);
}
}
事件测试类输出结果
10:00:02.586 [main] INFO com.test.event.MyEvent - msg:this is a event msg
事件总结:
当程序运行时,Spring会将发出的MyEvent事件转发给我们自定义 的MyListener进行进一步处理。这就是设计模式中的观察者模式。
- initApplicationEventMulticaster源码分析
initApplicationEventMulticaster方式比较简单,无非考虑两种情况
1、如果用户自定义了事件广播器,那么使用用户自定义的事件广播器。
ApplicationEventMulticaster。
2、如果用户没有自定义了事件广播器,那么使用默认的
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的multicastEvent方法来广播事件,遍历所有监听器,并使用监听器中的onApplicationEvent方法来进行监听器的处理。而对于每个监听器来说其实都可以获取到产生的事件,但是是否进行处理则由事件监听器来决定。
14、注册监听器
之前在介绍Spring的广播器时反复提到了事件监听器,那么在Spring注册监听器的时候,又做了哪些操作呢?
- registerListeners源码分析
protected void registerListeners() {
// 首先注册静态指定的监听器。
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 不要在这里初始化FactoryBeans:我们需要保留所有常规bean,未初始化,以让后置处理器应用于它们!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 发布早期的应用程序事件,现在我们终于有一个ApplicationEventMulticaster
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
15、初始化非延迟加载单例
- finishBeanFactoryInitialization源码分析
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 这个上下文的初始化转换服务。
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));
}
// 如果没有bean后处理器,注册一个默认的嵌入式值解析器
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);
}
// 停止使用临时类加载器进行类型匹配
beanFactory.setTempClassLoader(null);
// 允许缓存所有的bean定义元数据,不期望有进一步的更改。
beanFactory.freezeConfiguration();
// 实例化所有剩余的(非惰性初始化)单例
beanFactory.preInstantiateSingletons();
}
- ConversionService使用案例
定义转换器
package com.test.converter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @Description: 自定义日期转换器
* @Author: Janson
* @Date: 2020/4/19 10:49
**/
@Slf4j
public class String2DateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
log.info("convert before source:{}", source);
Date parse = simpleDateFormat.parse(source);
log.info("convert after parse:{}", parse);
return parse;
} catch (ParseException e) {
log.info("parse String to date error", e);
return null;
}
}
}
资源配置文件bean.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.xsd">
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.test.converter.String2DateConverter"></bean>
</list>
</property>
</bean>
</beans>
转换器测试类
package com.test;
import com.test.converter.String2DateConverter;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.util.Assert;
import java.util.Date;
/**
* @Description: 自定义日期转换器测试类
* @Author: Janson
* @Date: 2020/4/19 10:57
**/
public class String2DateConverterTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new String2DateConverter());
Date convert = conversionService.convert("2020-04-19 11:03:11", Date.class);
Assert.isAssignable(convert.getClass(),Date.class);
}
}
转换器测试类输出
11:22:45.040 [main] INFO com.test.converter.String2DateConverter - convert before source:2020-04-19 11:03:11
11:22:45.048 [main] INFO com.test.converter.String2DateConverter - convert after parse:Sun Apr 19 11:03:11 CST 2020
- preInstantiateSingletons源码分析
public void preInstantiateSingletons() throws BeansException {
if (logger.isDebugEnabled()) {
logger.debug("Pre-instantiating singletons in " + this);
}
// 遍历一个副本以允许init方法,而init方法反过来注册新的bean定义。虽然这可能不是常规的工厂引导的一部分,但它在其他方面也可以正常工作
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 触发所有非惰性单例bean的初始化
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);
}
}
}
// 为所有适用的bean触发初始化后回调
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();
}
}
}
}
16、完成刷新finishRefresh
在Spring中还提供了Lifecycle接口,Lifecycle中包含了start/stop方法,实现此接口后Spring会保证在启动的时候调用其start方法开始生命周期,并在Spring关闭的时候调用stop方法来结束生命周期,通常用来配置后台程序,在启动后一直运行(如对MQ进行轮询等)。而ApplicationContext的初始化最后正是保证了这一功能的实现。
- finishRefresh源码分析
protected void finishRefresh() {
// 清除上下文级的资源缓存(例如来自扫描的ASM元数据)
clearResourceCaches();
// 为此上下文初始化生命周期处理器。
initLifecycleProcessor();
// 首先将refresh传播到生命周期处理器
getLifecycleProcessor().onRefresh();
// 发布最终事件
publishEvent(new ContextRefreshedEvent(this));
// 如果活跃,请参与LiveBeansView MBean
LiveBeansView.registerApplicationContext(this);
}
initLifecycleProcessor
当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 + "]");
}
}
}
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();
}
}
}
publishEvent
当完成ApplicationContext初始化的时候,要通过Spring中的事件发布机制来发出ContextRefreshedEvent事件,以保证对应的监听器可以做进一步的逻辑处理。
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);
}
// 必要时将事件装饰为ApplicationEvent
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// 如果可能的话,现在就多播——或者在初始化多播之后延迟多播
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// 也可以通过父上下文发布事件。
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
17、总结
到这里,Spring5源码之ApplicationContext分析的初始化和刷新过程就已经讲完了,文章中总共分了16个目录来重点分析ApplicationContext的核心功能逻辑和开发过程中常用的案例来重新认识源码的执行过程。如果各位读者在看文章的过程中有什么问题或者文章中有分析不到位的地方,欢迎评论留言,相互学习,多谢。
参考文献
Spring源码深度解析
如果您觉得有帮助,欢迎点赞哦 ~ ~ 多谢~