ApplicationContext 和 BeanFactory 两者都是用于加载 bean 的,相比之下,ApplicationContext 除了包含 BeanFactory 的所有功能之外,还提供了更多的扩展功能。
那么 ApplicationContext 比 BeanFactory 多出了哪些功能呢?
写法上的不同:
BeanFactory
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring/app-context.xml"));
TestBean testBean = (TestBean) beanFactory.getBean("testBean");
System.out.println(testBean);
ApplicationContext
ApplicationContext bf = new ClassPathXmlApplicationContext("spring/app-context.xml");
TestBean testBean1 = (TestBean)bf.getBean("testBean");
System.out.println(testBean1);
下面我们以 ClassPathXmlApplicationContext 为切入点,来对整体功能进行分析。
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[]{configLocation}, true, (ApplicationContext)null);
}
public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
this(configLocations, true, (ApplicationContext)null);
}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
super(parent);
this.setConfigLocations(configLocations);
if (refresh) {
this.refresh();
}
}
可以看到首先是设置路径,然后解析和功能的实现都在 refresh() 中实现。
ClassPathXmlApplicationContext 支持多个配置文件以数组的形式同时传入:
public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for(int i = 0; i < locations.length; ++i) {
//解析给定路径
this.configLocations[i] = this.resolvePath(locations[i]).trim();
}
} else {
this.configLocations = null;
}
}
如果数组中包含特殊符号,如${var},那么在 resolvePath 中会搜寻匹配的系统变量进行替换。
设置路径之后,便可以根据路径对配置文件进行解析,以及各种功能的实现了,我们来分析 refresh() 函数。
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
//准备刷新的上下文环境
this.prepareRefresh();
//初始化 beanFactory,并进行 XML 文件读取
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//对 beanFactory 进行各种功能填充
this.prepareBeanFactory(beanFactory);
try {
//子类覆盖方法做额外处理
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
//激活各种 BeanFactory 处理器
this.invokeBeanFactoryPostProcessors(beanFactory);
//注册拦截 Bean 创建时的后置处理器,这里只是注册,真正的调用是在 getBean 的时候
this.registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
//为上下文初始化 Message 源,即不同语言的消息体,国际化处理
this.initMessageSource();
//初始化应用消息广播器,并放入 “ApplicationEventMulticaster” bean 中
this.initApplicationEventMulticaster();
//留给子类来初始化其他的 bean
this.onRefresh();
//在所有注册的 bean 中查找 Listener bean,注册到消息广播器中
this.registerListeners();
//初始化剩下的单实例(非惰性的)
this.finishBeanFactoryInitialization(beanFactory);
//完成刷新过程,通知声明周期处理器 lifecycleProcessor 刷新过程,同时发出
//ContextRefreshEvent 通知别人
this.finishRefresh();
} catch (BeansException var10) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
}
//出异常,销毁所有 bean
this.destroyBeans();
//取消刷新
this.cancelRefresh(var10);
throw var10;
} finally {
//重置缓存
this.resetCommonCaches();
contextRefresh.end();
}
}
}
下面概括一下 ClassPathXmlApplicationContext 初始化的步骤:
接下来具体分析下每个步骤的具体功能。
prepareRefresh 函数主要是做些准备工作,例如对系统属性及环境变量的初始化及验证。
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (this.logger.isDebugEnabled()) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Refreshing " + this);
} else {
this.logger.debug("Refreshing " + this.getDisplayName());
}
}
//留给子类覆盖
this.initPropertySources();
//验证需要的属性文件是否已经放入到环境中
this.getEnvironment().validateRequiredProperties();
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet(this.applicationListeners);
} else {
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
this.earlyApplicationEvents = new LinkedHashSet();
}
咋一看这个步骤好像没什么作用,因为 initPropertySources() 是空函数,this.getEnvironment().validateRequiredProperties() 也因为没有验证的属性而没有做任何处理。但是如果这个函数用好了,作用还是很大的,我们需要来探讨下怎么使用它?首先我们研究下这个函数里面各个步骤的作用。
我们举例说明 validateRequiredProperties 的验证功能。
**场景描述:**工程运行过程中用到的某个设置(例如 VAR)是从系统环境变量中取得的,而如果用户没有在系统环境变量中配置这个参数,那么工程不会工作。这样的场景下,我们可以自定义类:
package com.luo.spring.guides.helloworld.applicationcontext.validate.required;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author : archer
* @date : Created in 2022/11/29 16:03
* @description :
*/
public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
public MyClassPathXmlApplicationContext(String... configLocations){
super(configLocations);
}
@Override
protected void initPropertySources() {
//添加验证要求
getEnvironment().setRequiredProperties("VAR");
}
}
测试
package com.luo.spring.guides.helloworld.applicationcontext.validate.required;
import com.luo.spring.guides.helloworld.common.TestBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author : archer
* @date : Created in 2022/11/29 16:07
* @description :
*/
public class Main {
public static void main(String[] args) {
ApplicationContext bf = new MyClassPathXmlApplicationContext("spring/app-context.xml");
TestBean testBean1 = (TestBean)bf.getBean("testBean");
System.out.println(testBean1);
}
}
//输出 Exception in thread "main" org.springframework.core.env.MissingRequiredPropertiesException: The following properties were declared as required but could not be resolved: [VAR]
obtainFreshBeanFactory 是实现 BeanFactory 的地方,经过此函数后,ApplicationContext 就包含了 BeanFactory 的全部功能了。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//初始化 BeanFactory ,并进行 XML 文件读取,并将得到的 BeanFactory 记录到当前实体的属性中
this.refreshBeanFactory();
// 返回 BeanFactory
return this.getBeanFactory();
}
protected final void refreshBeanFactory() throws BeansException {
if (this.hasBeanFactory()) {
this.destroyBeans();
this.closeBeanFactory();
}
try {
//创建 DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
//为了序列化指定 id,如果需要的话,让 BeanFactory 从 id 反序列化到 BeanFactory 对象
beanFactory.setSerializationId(this.getId());
//定制 BeanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象、循环依赖
this.customizeBeanFactory(beanFactory);
//初始化 DocumentReader,并进行 XML 文件读取及解析
this.loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
} catch (IOException var2) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var2);
}
}
我们详细分析上面每个步骤。
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
//如果属性 allowBeanDefinitionOverriding 不为 null,设置给 beanFactory 对象相应属性,
//此属性含义:是否允许覆盖同名称的不同定义的对象
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//如果属性 allowCircularReferences 不为 null,设置给 beanFactory 对象相应属性,
//此属性含义:是否允许 bean 之间存在循环依赖
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
想要实现相应的设置,可以自己在实现的子类中使用方法覆盖:
package com.luo.spring.guides.helloworld.applicationcontext.validate.required;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author : archer
* @date : Created in 2022/11/29 16:03
* @description :
*/
public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
public MyClassPathXmlApplicationContext(String... configLocations){
super(configLocations);
}
@Override
protected void initPropertySources() {
//添加验证要求
getEnvironment().setRequiredProperties("VAR");
}
@Override
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
super.setAllowBeanDefinitionOverriding(false);
super.setAllowCircularReferences(false);
super.customizeBeanFactory(beanFactory);
}
}
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
//为指定 BeanFactory 创建 XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
//对 beanDefinitionReader 进行环境变量的设置
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
//对 BeanDefinitionReader 进行设置,可以被子类覆盖
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
在初始化 DefaultListableBeanFactory 和 XmlBeanDefinitionReader 后,就可以进行配置文件的读取了。
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
到 XmlBeanDefinitionReader#loadBeanDefinitions 这一步,就到之前我们分析 XmlBeanFactory 解析配置文件的步骤了,这里不再赘述。
进入 prepareBeanFactory 前,Spring 已经完成了对配置的解析,而 ApplicationContext 在功能上的扩展也由此展开。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
//设置 beanFactory 的 classLoader 为当前 context 的classLoader
beanFactory.setBeanClassLoader(getClassLoader());
if (!shouldIgnoreSpel) {
//设置 beanFactory 的表达式语言处理器,Spring 3 增加了表达式语言的支持
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
}
//为 beanFactory 增加一个默认的 PropertyEditor,这个主要是对 bean 的属性等设置管理的一个工具
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
//增加 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);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
//设置几个自动装配的特殊规则
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
//将用于检测内部 bean 的早期后处理器注册为 ApplicationListeners。
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
//检测 LoadTimeWeaver 和 增加对 AspectJ 的支持
if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
//为类型匹配设置一个临时的ClassLoader。
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// Register default environment beans.
//注册默认的系统环境系列的 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());
}
}
上面函数主要增加了如下拓展:
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
Spring 表达式语言全称为 Spring Expression Language,简称 SpEl。它能在运行时构建复杂表达式、存取对象图属性、对象方法调用等,并且能与 Spring 功能完美整合(比如用来配置 bean 定义)。SpEL 是单独的模块,只依赖于 core 模块。可以单独使用。
示例
<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.xsd">
<bean id="testBean" class="com.luo.spring.guides.common.TestBean"/>
<bean id="spelTestBean" class="com.luo.spring.guides.spel.SpelTestBean">
<property name="testBean" value="#{testBean}"/>
bean>
beans>
等价于
<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.xsd">
<bean id="testBean" class="com.luo.spring.guides.common.TestBean"/>
<bean id="spelTestBean" class="com.luo.spring.guides.spel.SpelTestBean">
<property name="testBean" ref="testBean"/>
bean>
beans>
源码中是通过 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()))
来注册语言解析器。
注册完后是什么时候调用此解析器来解析的呢?Spring 中在 bean 进行初始化的时候会有属性填充这一步,这一步中的 AbstractAutowireCapableBeanFactory 类的 applyPropertyValues 函数就是用来完成这个调用解析器解析的功能的。具体源码是在下面这一步:
@Nullable
protected Object evaluateBeanDefinitionString(@Nullable String value, @Nullable BeanDefinition beanDefinition) {
if (this.beanExpressionResolver == null) {
return value;
}
Scope scope = null;
if (beanDefinition != null) {
String scopeName = beanDefinition.getScope();
if (scopeName != null) {
scope = getRegisteredScope(scopeName);
}
}
return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
}
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
Spring DI 注入的时候,像 Date 类型的属性因为无法识别,是注入不进来的,因为 Java 类中的属性是 Date 类型,但是 XML 中的配置确实 String 类型,所以会报异常。
Spring 针对此问题提供了两种解决方案。
a、编写自定义属性编辑器
package com.luo.spring.guides.propertyeditor.custom;
import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DatePropertyEditor extends PropertyEditorSupport {
private String format = "yyyy-MM-dd";
public void setFormat(String format) {
this.format = format;
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
SimpleDateFormat dateFormatter = new SimpleDateFormat(format);
try {
Date d = dateFormatter.parse(text);
this.setValue(d);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
2、将自定义属性编辑器注册到 Spring 中
<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.xsd">
<bean name="customEditorConfigurer"
class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date">
<bean class="com.luo.spring.guides.propertyeditor.custom.DatePropertyEditor">
<property name="format" value="yyyy-MM-dd"/>
bean>
entry>
map>
property>
bean>
beans>
1、定义属性编辑器
package com.luo.spring.guides.propertyeditor.custom;
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author : archer
* @date : Created in 2022/12/16 15:17
* @description :
*/
public class DatePropertyEditorRegistrar implements PropertyEditorRegistrar {
@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
registry.registerCustomEditor(Date.class,
new CustomDateEditor(dateFormatter, true));
}
}
2、注册到 Spring 中
<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.xsd">
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer" >
<property name="propertyEditorRegistrars">
<list>
<bean class="com.luo.spring.guides.propertyeditor.custom.DatePropertyEditorRegistrar"/>
list>
property>
bean>
beans>
ResourceEditorRegistrar#registerCustomEditors
@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
doRegisterEditor(registry, Resource.class, baseEditor);
doRegisterEditor(registry, ContextResource.class, baseEditor);
doRegisterEditor(registry, WritableResource.class, baseEditor);
doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
doRegisterEditor(registry, Path.class, new PathEditor(baseEditor));
doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor));
doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));
ClassLoader classLoader = this.resourceLoader.getClassLoader();
doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));
if (this.resourceLoader instanceof ResourcePatternResolver) {
doRegisterEditor(registry, Resource[].class,
new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader, this.propertyResolver));
}
}
/**
* Override default editor, if possible (since that's what we really mean to do here);
* otherwise register as a custom editor.
*/
private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
if (registry instanceof PropertyEditorRegistrySupport) {
((PropertyEditorRegistrySupport) registry).overrideDefaultEditor(requiredType, editor);
}
else {
registry.registerCustomEditor(requiredType, editor);
}
}
doRegisterEditor 函数中,可以看到上面提到的自定义属性中使用的关键代码。ResourceEditorRegistrar#registerCustomEditors 只是注册了一系列常用类型的属性编辑器。但是 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); 仅仅是注册了 ResourceEditorRegistrar 类的实例,并没有调用ResourceEditorRegistrar#registerCustomEditors 方法进行注册,那到底是什么时候注册的呢?
我们查看下 ResourceEditorRegistrar#registerCustomEditors 的调用链,可以追踪到 AbstractBeanFactory#initBeanWrapper 方法,这是在 bean 初始化时使用的一个方法,前面已经分析过了,getBean 的时候会有调用。主要是在将 BeanDefinition 转换为 BeanWrapper 后用于对属性的填充。到此,逻辑上已经很清晰了,bean 初始化后会调用 ResourceEditorRegistrar#registerCustomEditors 方法进行鼻梁的通用属性编辑器注册,注册后,在属性填充环节,便可让 Spring 使用这些编辑器进行属性的解析了。
BeanWrapper 用于封装 bean,它间接继承了 PropertyEditorRegistry 类型,BeanWrapper 的默认实现类型是 BeanWrapperImpl,BeanWrapperImpl 除了实现 BeanWrapper 接口外还继承了 PropertyEditorRegistrySupport。在 PropertyEditorRegistrySupport 中有这样一个方法:
private void createDefaultEditors() {
this.defaultEditors = new HashMap<>(64);
// Simple editors, without parameterization capabilities.
// The JDK does not contain a default editor for any of these target types.
this.defaultEditors.put(Charset.class, new CharsetEditor());
this.defaultEditors.put(Class.class, new ClassEditor());
this.defaultEditors.put(Class[].class, new ClassArrayEditor());
this.defaultEditors.put(Currency.class, new CurrencyEditor());
this.defaultEditors.put(File.class, new FileEditor());
this.defaultEditors.put(InputStream.class, new InputStreamEditor());
if (!shouldIgnoreXml) {
this.defaultEditors.put(InputSource.class, new InputSourceEditor());
}
this.defaultEditors.put(Locale.class, new LocaleEditor());
this.defaultEditors.put(Path.class, new PathEditor());
this.defaultEditors.put(Pattern.class, new PatternEditor());
this.defaultEditors.put(Properties.class, new PropertiesEditor());
this.defaultEditors.put(Reader.class, new ReaderEditor());
this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor());
this.defaultEditors.put(TimeZone.class, new TimeZoneEditor());
this.defaultEditors.put(URI.class, new URIEditor());
this.defaultEditors.put(URL.class, new URLEditor());
this.defaultEditors.put(UUID.class, new UUIDEditor());
this.defaultEditors.put(ZoneId.class, new ZoneIdEditor());
// Default instances of collection editors.
// Can be overridden by registering custom instances of those as custom editors.
this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class));
this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));
this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class));
this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));
this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class));
// Default editors for primitive arrays.
this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());
this.defaultEditors.put(char[].class, new CharArrayPropertyEditor());
// The JDK does not contain a default editor for char!
this.defaultEditors.put(char.class, new CharacterEditor(false));
this.defaultEditors.put(Character.class, new CharacterEditor(true));
// Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor.
this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false));
this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true));
// The JDK does not contain default editors for number wrapper types!
// Override JDK primitive number editors with our own CustomNumberEditor.
this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false));
this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true));
this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false));
this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true));
this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false));
this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true));
this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false));
this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true));
this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false));
this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));
this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false));
this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true));
this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));
this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));
// Only register config value editors if explicitly requested.
if (this.configValueEditorsActive) {
StringArrayPropertyEditor sae = new StringArrayPropertyEditor();
this.defaultEditors.put(String[].class, sae);
this.defaultEditors.put(short[].class, sae);
this.defaultEditors.put(int[].class, sae);
this.defaultEditors.put(long[].class, sae);
}
}
它的作用一目了然,就是定义了一些常用的属性编辑器,并自动注册,如果我们定义的 bean 中的某个属性类型不在上面的常用配置中,我们就需要进行个性化属性编辑器的注册。
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
这里是注册 ApplicationContextAwareProcessor,真正的处理逻辑在 ApplicationContextAwareProcessor 类中。在 bean 实例化的时候,即 Spring 激活 bean 的 init-method 的前后,会调用 BeanPostProcessor 的 postProcessBeforeInitialization 和 postProcessAfterInitialization 方法。ApplicationContextAwareProcessor 没有对 postProcessAfterInitialization 做什么逻辑,所以我们重点分析 postProcessBeforeInitialization 方法。
@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
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) {
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);
}
}
postProcessBeforeInitialization 方法中调用了 invokeAwareInterfaces 方法。invokeAwareInterfaces 方法的逻辑很明显,实现了这些 aware 的 bean,可以在初始化之后,获取相对应的资源。
Spring 将 ApplicationContextAwareProcessor 注册后,其 invokeAwareInterfaces 方法内间接调用的 Aware 类已经不是普通的 bean 了。因此需要在依赖注入的时候,将它们忽略。
//设置几个忽略自动装配的接口
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);
有了忽略依赖,也会有注册依赖的功能。当注册了依赖解析后,后面进行 bean 的属性注入的时候,一旦检测到属性为注册过的依赖类型,便会将此事保存的实例,注册进去。
//设置几个自动装配的特殊规则
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
BeanFactory 作为 Spring 容器功能的基础,用于存放所有已加载的 bean,为了保证扩展性,Spring 针对 BeanFactory 做了大量的扩展。
示例
app-context-processor.xml
<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.xsd">
<bean id="testBean" class="com.luo.spring.guides.post.processor.PostProcessorTestBean">
<property name="name">
<value>${bean.name}value>
property>
bean>
<bean id="testBeanHandler" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>postprocessor/bean.propertiesvalue>
list>
property>
<property name="fileEncoding">
<value>utf-8value>
property>
bean>
beans>
bean.properties
bean.name=我是小小罗
PostProcessorTestBean.java
package com.luo.spring.guides.post.processor;
import lombok.Data;
/**
* @author : archer
* @date : Created in 2023/1/3 11:36
* @description :
*/
@Data
public class PostProcessorTestBean {
private String name;
}
测试
package com.luo.spring.guides.post.processor;
import org.springframework.context.support.GenericXmlApplicationContext;
import java.util.Locale;
/**
* @author : archer
* @date : Created in 2023/1/3 11:38
* @description :
*/
public class Main {
public static void main(String... args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:postprocessor/app-context-processor.xml");
ctx.refresh();
PostProcessorTestBean testBean = ctx.getBean("testBean", PostProcessorTestBean.class);
System.out.println(testBean.getName());
ctx.close();
}
}
输出
我是小小罗
场景:配置敏感词,展示时忽略
package com.luo.spring.guides.post.processor.custom;
import lombok.Data;
import lombok.ToString;
/**
* @author : archer
* @date : Created in 2023/1/9 10:41
* @description :
*/
@ToString
@Data
public class SimplePostBean {
private String connectionString;
private String username;
private String password;
}
package com.luo.spring.guides.post.processor.custom;
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;
/**
* @author : archer
* @date : Created in 2023/1/3 13:06
* @description :
*/
public class ObscenityRemovingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private Set<String> obscenities;
public ObscenityRemovingBeanFactoryPostProcessor() {
this.obscenities = 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(isObscene(strVal)) return "*****";
return strVal;
}
};
BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
visitor.visitBeanDefinition(bd);
}
}
public boolean isObscene(Object value){
String potentialObscenity = value.toString().toUpperCase();
return this.obscenities.contains(potentialObscenity);
}
public void setObscenities(Set<String> obscenities){
this.obscenities.clear();
for (String obscenity : obscenities) {
this.obscenities.add(obscenity.toUpperCase());
}
}
}
<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.xsd">
<bean id="bfpp" class="com.luo.spring.guides.post.processor.custom.ObscenityRemovingBeanFactoryPostProcessor">
<property name="obscenities">
<set>
<value>bollocksvalue>
<value>winkyvalue>
<value>bumvalue>
<value>microsoftvalue>
set>
property>
bean>
<bean id="simpleBean" class="com.luo.spring.guides.post.processor.custom.SimplePostBean">
<property name="connectionString">
<value>bollocksvalue>
property>
<property name="username">
<value>microsoftvalue>
property>
<property name="password">
<value>passwordvalue>
property>
bean>
beans>
测试类
package com.luo.spring.guides.post.processor.custom;
import com.luo.spring.guides.post.processor.PostProcessorTestBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
/**
* @author : archer
* @date : Created in 2023/1/9 10:51
* @description :
*/
public class Main {
public static void main(String... args) {
ConfigurableListableBeanFactory ctx = new XmlBeanFactory(new ClassPathResource("postprocessor/custom/app-context-processor-custom.xml"));
BeanFactoryPostProcessor bfpp = (BeanFactoryPostProcessor) ctx.getBean("bfpp");
bfpp.postProcessBeanFactory(ctx);
System.out.println( ctx.getBean("simpleBean"));
}
}
输出
SimplePostBean(connectionString=
*****
, username=*****
, password=password)
//子类覆盖方法做额外处理:方便业务上做进一步的拓展
this.postProcessBeanFactory(beanFactory);
//激活各种 BeanFactory 处理器
this.invokeBeanFactoryPostProcessors(beanFactory);
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors 源码如下
//beanFactoryPostProcessors 硬编码注册的后处理器
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
//对 BeanDefinitionRegistry 类型的处理
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//beanFactoryPostProcessors 硬编码注册的后处理器
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor;
//对于 BeanDefinitionRegistryPostProcessor 类型,在 BeanFactoryPostProcessor 的基础上还有自己定义的方法,需要先调用
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
//记录常规的 BeanFactoryPostProcessor
regularPostProcessors.add(postProcessor);
}
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
//首先,调用实现 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, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
//接下来,调用实现 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, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
//最后,调用所有其他 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();
}
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
//现在,调用到目前为止处理的所有处理器的 postProcessBeanFactory 回调。
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
//非 BeanDefinitionRegistry 类型的处理,处理的是入参的 beanFactoryPostProcessors,即硬编码注册的后处理器
// Invoke factory processors registered with the context instance.
//调用在上下文实例中注册的工厂处理器。
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
将实现 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)) {
// 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);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
//首先,调用实现 PriorityOrdered 的 BeanFactoryPostProcessors。
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
//接下来,调用实现 Ordered 的 BeanFactoryPostProcessors。
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
//最后,调用所有其他 BeanFactoryPostProcessor。
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
清除缓存的合并 bean 定义,因为后处理器可能已经修改了原始元数据,例如替换值中的占位符...
beanFactory.clearMetadataCache();
}
对方法进行分解,大致流程分为如下两步:
(1)、对于 BeanDefinitionRegistry 类的特殊处理
a、对于硬编码注册的后处理器的处理
b、记录后处理器主要使用了2个List完成
补充:**currentRegistryProcessors:**记录通过配置方式注册的 BeanDefinitionRegistryPostProcessor 类型的处理器,对于配置方式注册的,添加后会进行 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 方法调用
c、对以上所记录的 List 中的后处理器统一调用 BeanFactoryPostProcessor#postProcessBeanFactory 方法
(2)、对普通的 BeanFactoryPostProcessor 的处理
package com.luo.spring.guides.common;
/**
* @author : archer
* @date : Created in 2023/1/9 15:47
* @description :
*/
public class TestBean1 {
}
package com.luo.spring.guides.common;
/**
* @author : archer
* @date : Created in 2023/1/9 15:47
* @description :
*/
public class TestBean {
}
package com.luo.spring.guides.post.processor.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
/**
* @author : archer
* @date : Created in 2023/1/9 15:39
* @description :
*/
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("==========");
return null;
}
}
<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.xsd">
<bean id="myiabpp" class="com.luo.spring.guides.post.processor.bean.MyInstantiationAwareBeanPostProcessor"/>
<bean id="testBean" class="com.luo.spring.guides.common.TestBean"/>
<bean id="testBean1" class="com.luo.spring.guides.common.TestBean1"/>
beans>
测试
package com.luo.spring.guides.post.processor.bean;
import com.luo.spring.guides.common.TestBean;
import org.springframework.context.support.GenericXmlApplicationContext;
/**
* @author : archer
* @date : Created in 2023/1/9 15:42
* @description :
*/
public class Main {
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:postprocessor/bean/bean-processor.xml");
ctx.refresh();
ctx.close();
}
}
输出
==========
==========
可以看到使用 ApplicationContext 容器每初始化一个 bean,都会执行 MyInstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 方法,而使用 BeanFactory 方式进行 bean 初始化,则不会执行方法。
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
PostProcessorRegistrationDelegate#registerBeanPostProcessors 源码如下
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
//BeanPostProcessorChecker 是一个普通的信息打印,可能会有些情况,
//当 Spring 的配置中的后处理器,还没有被注册,就已经开始了 bean 的初始化时,
//便会打印出 BeanPostProcessorChecker 中设定的信息
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
//使用 PriorityOrdered 保证顺序
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
//使用 Ordered 保证顺序
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);
}
}
// First, register the BeanPostProcessors that implement PriorityOrdered.
//首先,注册实现 PriorityOrdered 的 BeanPostProcessors。
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implement Ordered.
//接下来,注册实现 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);
// Now, register all regular BeanPostProcessors.
//然后,注册所有余下的普通 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);
// Finally, re-register all internal BeanPostProcessors.
//最后,重新注册所有内部的 BeanPostProcessor。
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
// 将用于检测内部 bean 的后处理器重新注册为 ApplicationListeners,将其移动到处理器链的末尾(用于获取代理等)。
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
因为 BeanPostProcessor 在这里只是进行注册,调用是在 bean 初始化的时候,所以这里就没有硬编码方式的实现了。
a、定义资源文件
message.properties
test=test
message_zh_CN.properties
//test=测试
test=\u6d4b\u8bd5
message_en_US.properties
test=test
b、定义配置文件
<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"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
p:basenames-ref="basenames"/>
<util:list id="basenames">
<value>messagevalue>
util:list>
beans>
c、使用 ApplicationContext 访问国际化信息
package com.luo.spring.guides.messagesource.i18n;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.Properties;
/**
* @author : archer
* @date : Created in 2023/1/9 16:25
* @description :
*/
@Slf4j
public class I18nMain {
public static void main(String[] args) {
String[] configs = {"i18n/i18n.xml"};
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(configs);
String usStr = applicationContext.getMessage("test", null, Locale.US);
String cnStr = applicationContext.getMessage("test", null, Locale.CHINA);
System.out.println(cnStr);
System.out.println(usStr);
}
}
输出
测试
test
/**
* Initialize the MessageSource.
* Use parent's if none defined in this context.
*/
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
//如果在配置中已经配置了 messageSource,那么将 messageSource 提取并记录在 this.messageSource 中
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// Make MessageSource aware of parent MessageSource.
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// Only set parent context as parent MessageSource if no parent MessageSource
// registered already.
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isTraceEnabled()) {
logger.trace("Using MessageSource [" + this.messageSource + "]");
}
}
else {
// Use empty MessageSource to be able to accept getMessage calls.
//如果用户没有定义,就使用临时的 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 + "]");
}
}
}
a、定义监听事件
package com.luo.spring.guides.event.multicaster;
import org.springframework.context.ApplicationEvent;
/**
* @author : archer
* @date : Created in 2023/1/9 17:59
* @description :
*/
public class TestEvent extends ApplicationEvent {
private String msg;
public TestEvent(Object source, String msg) {
super(source);
this.msg = msg;
}
public void print() {
System.out.println("received: " + msg);
}
}
b、定义监听器
package com.luo.spring.guides.event.multicaster;
import org.springframework.context.ApplicationListener;
/**
* @author : archer
* @date : Created in 2023/1/9 18:07
* @description :
*/
public class TestListener implements ApplicationListener<TestEvent> {
@Override
public void onApplicationEvent(TestEvent event) {
event.print();
}
}
c、添加配置文件
<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="testListener" class="com.luo.spring.guides.event.multicaster.TestListener"/>
beans>
d、测试
package com.luo.spring.guides.event.multicaster;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author : archer
* @date : Created in 2023/1/9 19:43
* @description :
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("event/listener.xml");
ctx.publishEvent(new TestEvent("hello","msg"));
}
}
输出
received: i am a message
/**
* Initialize the ApplicationEventMulticaster.
* Uses SimpleApplicationEventMulticaster if none defined in the context.
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
*/
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.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
//若用户没有定义自定义广播器,则使用默认的 SimpleApplicationEventMulticaster
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
SimpleApplicationEventMulticaster 广播事件的源码如下
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
/**
* Invoke the given listener with the given event.
* @param listener the ApplicationListener to invoke
* @param event the current event to propagate
* @since 4.1
*/
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
//异常捕获要执行的方法
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
//调用 ApplicationListener 的 onApplicationEvent 方法
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
(event instanceof PayloadApplicationEvent &&
matchesClassCastMessage(msg, ((PayloadApplicationEvent) event).getPayload().getClass()))) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception.
Log loggerToUse = this.lazyLogger;
if (loggerToUse == null) {
loggerToUse = LogFactory.getLog(getClass());
this.lazyLogger = loggerToUse;
}
if (loggerToUse.isTraceEnabled()) {
loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
两种方式注册监听器
/**
* Add beans that implement ApplicationListener as listeners.
* Doesn't affect other listeners, which can be added without being beans.
*/
protected void registerListeners() {
// Register statically specified listeners first.
//硬编码方式注册的监听器
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
//配置文件注册的监听器
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
//广播器来发布一些早期的应用程序事件,容器启动就发布的事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
/**
* Finish the initialization of this context's bean factory,
* initializing all remaining singleton beans.
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
//为此上下文初始化转换服务(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));
}
// Register a default embedded value resolver if no BeanFactoryPostProcessor
// (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
//如果没有 BeanFactoryPostProcessor,则注册一个默认的嵌入值解析器
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
//尽早初始化 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);
// Allow for caching all bean definition metadata, not expecting further changes.
//冻结所有的 beanDefinition 的元数据,说明注册的 bean 定义将不被修改或任何进一步的处理
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
//初始化剩余的非懒加载的单例
beanFactory.preInstantiateSingletons();
}
之前有使用过自定义类型转换器来把配置文件读取的 String 类型转换为 Date 类型,现在来介绍另一种方式,使用 Conventer。先来看一个简单的示例
a、定义转换器与实例
package com.luo.spring.guides.converter;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author : archer
* @date : Created in 2023/1/9 20:21
* @description :
*/
public class String2DateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
return dateFormatter.parse(source);
} catch (ParseException e) {
e.printStackTrace();
return null;
}
}
}
package com.luo.spring.guides.converter;
import lombok.Data;
import java.util.Date;
/**
* @author : archer
* @date : Created in 2023/1/9 20:38
* @description :
*/
@Data
public class DateBean {
private Date date;
}
b、注册
<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.luo.spring.guides.converter.String2DateConverter"/>
list>
property>
bean>
<bean id="dateBean" class="com.luo.spring.guides.converter.DateBean">
<property name="date" value="2023-01-09 20:34:45"/>
bean>
beans>
c、测试
package com.luo.spring.guides.converter;
import com.luo.spring.guides.event.multicaster.TestEvent;
import lombok.Data;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.convert.support.DefaultConversionService;
import java.util.Date;
/**
* @author : archer
* @date : Created in 2023/1/9 20:32
* @description :
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("converter/converter.xml");
DateBean dateBean = (DateBean) ctx.getBean("dateBean");
System.out.println(dateBean.getDate());
}
}
输出
Mon Jan 09 20:34:45 CST 2023
@Override
public void freezeConfiguration() {
this.configurationFrozen = true;
this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
}
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
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();
}
}
}
/**
* Finish the refresh of this context, invoking the LifecycleProcessor's
* onRefresh() method and publishing the
* {@link org.springframework.context.event.ContextRefreshedEvent}.
*/
@SuppressWarnings("deprecation")
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
//清除上下文级资源缓存(例如来自扫描的 ASM 元数据)。
clearResourceCaches();
// Initialize lifecycle processor for this context.
//初始化生命周期处理器
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
//首先用生命周期处理器来启动所有实现了 Lifecycle 接口的 bean
getLifecycleProcessor().onRefresh();
// Publish the final event.
//发布事件
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
//参与 LiveBeansView MBean(如果激活)。
if (!NativeDetector.inNativeImage()) {
LiveBeansView.registerApplicationContext(this);
}
}
/**
* Initialize the LifecycleProcessor.
* Uses DefaultLifecycleProcessor if none defined in the context.
* @see org.springframework.context.support.DefaultLifecycleProcessor
*/
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.isTraceEnabled()) {
logger.trace("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.isTraceEnabled()) {
logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +
"[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");
}
}
}
@Override
public void onRefresh() {
startBeans(true);
this.running = true;
}
private void startBeans(boolean autoStartupOnly) {
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new TreeMap<>();
lifecycleBeans.forEach((beanName, bean) -> {
if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
int phase = getPhase(bean);
phases.computeIfAbsent(
phase,
p -> new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly)
).add(beanName, bean);
}
});
if (!phases.isEmpty()) {
phases.values().forEach(LifecycleGroup::start);
}
}
@Override
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
/**
* Publish the given event to all listeners.
* @param event the event to publish (may be an {@link ApplicationEvent}
* or a payload object to be turned into a {@link PayloadApplicationEvent})
* @param eventType the resolved event type, if known
* @since 4.2
*/
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}