在前面的内容中,我们针对BeanFactory
进行了深度的分析。那么,下面我们将针对BeanFactory的功能扩展类ApplicationContext
进行深度的分析。ApplicationConext与BeanFactory的功能相似,都是用于向IOC中加载Bean的。由于ApplicationConext的功能是大于BeanFactory的,所以在日常使用中,建议直接使用ApplicationConext即可。下面是两个类使用示例:
ApplicationConext
是接口,所以要分析其加载bean的流程,就可以从ClassPathXmlApplicationContext
入手,其构造函数如下所示:
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) {
super(parent);
setConfigLocations(configLocations); // 事情1:设置配置加载路径
if (refresh) refresh(); // 事情2:所有功能的初始化操作
}
在上面的构造方法中,主要做了两个事情:
【事情1】设置配置的加载路径
;
【事情2】执行ApplicationConext中,所有功能的初始化
操作;
下面文章的内容,我们就是会针对这两部分做详细的解析:
该方法逻辑不多,主要就是为应用上下文ApplicationContext设置配置路径(config locations
),源码如下所示:
public void setConfigLocations(String... locations) { // 支持传入多个配置文件
if (locations != null) {
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++)
this.configLocations[i] = resolvePath(locations[i]).trim(); // 路径解析
} else
this.configLocations = null;
}
// 如果路径中包含特殊符号(如:${var}),那么在resolvePath方法中会搜寻匹配的系统变量并且进行替换操作
protected String resolvePath(String path) {
// 调用AbstractPropertyResolver#resolveRequiredPlaceholders(path)方法
return getEnvironment().resolveRequiredPlaceholders(path);
}
在refresh()
方法中几乎包含了ApplicationContext中提供的全部功能,下面我们会针对这个方法进行详细的分析:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh(); /** 步骤1:为refresh操作做提前的准备工作 */
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); /** 步骤2:获得beanFactory实例对象 */
prepareBeanFactory(beanFactory); /** 步骤3:准备用于此上下文的beanFactory */
try {
postProcessBeanFactory(beanFactory); // 允许在上下文子类中对BeanFactory进行后置处理(空方法,可由子类实现)
invokeBeanFactoryPostProcessors(beanFactory); /** 步骤4:激活各种BeanFactory的后置处理器 */
registerBeanPostProcessors(beanFactory); /** 步骤5:注册各种Bean的后置处理器,在getBean时才会被调用 */
initMessageSource(); /** 步骤6:为上下文初始化消息源(即:国际化处理)*/
initApplicationEventMulticaster(); /** 步骤7:为上下文初始化应用事件广播器 */
onRefresh(); // 初始化特定上下文子类中的其他特殊bean(空方法,可由子类实现)
registerListeners(); /** 步骤8:在所有注册的bean中查找listener bean,并注册到消息广播器中 */
finishBeanFactoryInitialization(beanFactory); /** 步骤9:初始化剩下的单例(非惰性non-lazy-init)*/
finishRefresh(); /** 步骤10:完成refresh,通知lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知 */
}
catch (BeansException ex) {
destroyBeans(); // Destroy already created singletons to avoid dangling resources
cancelRefresh(ex); // Reset 'active' flag
throw ex;
}
finally {resetCommonCaches();}
}
}
下面我们来分析一下refresh()
方法中的prepareRefresh()
代码段的处理逻辑:
针对prepareRefresh()
方法来说,主要就包含如下注释的两个方法,看似没什么意义,但是如果我们自定义了ClassPathXmlApplicationContext类,那么可以通过重写initPropertySources()
方法,来增加逻辑代码:
protected void prepareRefresh() {
...
this.active.set(true);
initPropertySources(); // 空方法,可以由子类重写
getEnvironment().validateRequiredProperties(); /** 验证需要的属性文件是否都已经放入环境中 */
...
}
public void validateRequiredProperties() throws MissingRequiredPropertiesException {
this.propertyResolver.validateRequiredProperties();
}
public void validateRequiredProperties() {
MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
for (String key : this.requiredProperties)
// 如果环境中没有配置所需属性,则将缺失的属性放到ex中,并抛出异常
if (this.getProperty(key) == null)
ex.addMissingRequiredProperty(key);
if (!ex.getMissingRequiredProperties().isEmpty()) {throw ex;}
}
下面我们来分析一下refresh()
方法中的obtainFreshBeanFactory()
代码段的处理逻辑:
通过obtainFreshBeanFactory()
这个方法,ApplicationContext就已经拥有了BeanFactory的全部功能。而这个方法中也包含了前面我们介绍BeanFactory时候对于xml配置的加载过程。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory(); /** 初始化BeanFactory */
return getBeanFactory();
}
在refreshBeanFactory()
方法中,在基本容器的基础上,增加了是否允许覆盖 和 是否允许扩展的设置,并提供了注解 @Qualifier 和 @Autowired 的支持。
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {destroyBeans();closeBeanFactory();}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory(); // new一个beanFactory的实例对象
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory); // 定制化操作BeanFactory配置
loadBeanDefinitions(beanFactory); /** 初始化XmlBeanDefinitionReader,并进行xml配置文件读取及解析 */
this.beanFactory = beanFactory;
}
catch (IOException ex) {throw new ApplicationContextException(...);}
}
/** 该方法可以采用子类覆盖的方式改变里面的逻辑内容 */
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) // 设置是否允许覆盖同名称且不同定义的beanDefinition实例
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
if (this.allowCircularReferences != null) // 设置是否允许bean直接存在循环依赖
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
在loadBeanDefinitions(beanFactory)
方法中,执行了初始化XmlBeanDefinitionReader操作,并且进行xml配置文件读取及解析
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建XmlBeanDefinitionReader,用于后续对配置的读取操作
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
initBeanDefinitionReader(beanDefinitionReader); // 对beanDefinitionReader进行设置,可以被子类覆盖
loadBeanDefinitions(beanDefinitionReader); /** 加载xml配置信息 */
}
/** 对XmlBeanDefinitionReader进行设置(此方法可以由子类进行覆写) */
protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
reader.setValidating(this.validating); // validating = true
}
当获得了XmlBeanDefinitionReader之后,我们就可以通过loadBeanDefinitions(beanDefinitionReader)
方法对xml配置文件进行读取操作了。其中的reader.loadBeanDefinitions(...)
方法我们在前面的BeanFactory配置文件读取操作中已经解析过了,此处就不再赘述。
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 尝试获得xml配置文件的Resource实例集合,并进行配置加载
Resource[] configResources = getConfigResources();
if (configResources != null) reader.loadBeanDefinitions(configResources);
// 尝试获得xml配置文件路径集合,并进行配置加载
String[] configLocations = getConfigLocations();
if (configLocations != null) reader.loadBeanDefinitions(configLocations);
}
下面我们来分析一下refresh()
方法中的prepareBeanFactory()
代码段的处理逻辑:
当执行本方法之前,Spring已经完成了对配置的解析操作,而从本方法开始,ApplicationContext
在功能上的扩展也由此展开了。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 将当前上下文的classLoader作为beanFactory的classLoader
beanFactory.setBeanClassLoader(getClassLoader());
// 是否支持SpEL表达式解析,即:可以使用#{bean.xxx}的形式来调用相关属性值
if (!shouldIgnoreSpel)
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 添加1个属性编辑器,它是对bean的属性等设置管理的工具
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 添加1个bean的后置处理器
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 设置7个需要忽略自动装配的接口
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);
// 注册4个依赖
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 添加1个bean的后置处理器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// 增加对AspectJ的支持
if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 注册4个默认的系统环境bean
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) // environment
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) // systemProperties
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) // systemEnvironment
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) // applicationStartup
beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
}
SpEL全称是“Spring Expression Language”,它能在运行时构件复杂表达式
、存取对象图属性
、对象方法调用
等;它是单独模块,只依赖了core
模块,所以可以单独使用。SpEL使用 #{...} 作为界定符,所有在大括号中的字符都会被认定为SpEL,使用方式如下所示:
相当于:
在 prepareBeanFactory(beanFactory) 方法中,通过beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(...))
注册SpEL语言解析器,就可以对SpEL
进行解析了。
那么,在注册了解析器后,Spring又是在什么时候调用这个解析器进行解析操作的呢?调用方式如下图所示:
【解释】其实就是在Spring进行bean初始化的时候,有一个步骤是——属性填充(即:
populateBean()
),而在这一步中Spring会调用AbstractAutowireCapableBeanFactory#applyPropertyValues(...)
方法来完成功能。而就在这个方法中,会创建BeanDefinitionValueResolver
实例对象valueResolver来进行属性值的解析操作。同时,也是在这个步骤中,通过AbstractBeanFactory#evaluateBeanDefinitionString(...)
方法去完成SpEL的解析操作。
相关源码如下所示:
protected Object evaluateBeanDefinitionString(String value, BeanDefinition beanDefinition) {
if (this.beanExpressionResolver == null) return value;
Scope scope = null;
if (beanDefinition != null) {
String scopeName = beanDefinition.getScope();
if (scopeName != null) scope = getRegisteredScope(scopeName);
}
// 通过获得的beanExpressionResolver实例调用evaluate(...)方法执行解析操作
return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
}
下面我们继续来介绍一下beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
这行代码,那么通过调用的方法名称,我们可以猜到它的作用是给BeanFactory实例添加属性编辑器。那么,什么是属性编辑器呢? 在Spring加载bean的时候,可以把基本类型属性注入进来,但是对于类似Date这种复杂属性就无法被识别了。
我们假设有一个Schedule
类,其中包含了一个Date
类型的属性,如果采用默认加载方式的话,是无法将xml中配置的"2023-01-01"值转换为Date类型的。那么,下面我们就来演示一下如何通过自定义属性编辑器来让Spring在加载bean的时候,将String类型的值转换为Date类型的值。如下所示:
@Data
public class Schedule {
private String name;
private Date date; // 添加Date类型的属性
}
当我们运行的时候发现报错了,即:无法将配置文件中的String类型转换为Date类型:
那么,我们添加用来将String类型转换为Date类型
的属性编译器DatePropertyEditor,并将其注入到CustomEditorConfigurer中即可。
public class DatePropertyEditor implements PropertyEditorRegistrar {
@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}
}
在调用registerCustomEditor(...)
方法的时候,我们创建了CustomDateEditor实例对象,在此处我们只是来看一下它的类继承关系,下文还会涉及对它的介绍。
通过上面对于注册属性编辑器的配置,我们可以看到自定义的属性编辑器DatePropertyEditor
被保存到了CustomEditorConfigurer
的propertyEditorRegistrars属性中,那么由于CustomEditorConfigurer
类实现了BeanFactoryPostProcessor
接口,所以当bean初始化的时候,会调用它的postProcessBeanFactory(...)
方法,那么在这个方法中,会将propertyEditorRegistrars属性中的所有属性编辑器添加到beanFactory
中。
那么,我们在回头来看 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())) 的这行代码,其实也是同样的调用方式:
那么,我们分析到这一步之后,发现自定义属性编辑器都会保存到ConfigurableListableBeanFactory实例对象beanFactory
的变量propertyEditorRegistrars中。那么问题来了——保存我们知道了,那什么时候属性编辑器会被调用呢? 其实就是在初始化bean的时候,在initBeanWrapper(...)
方法中,会被调用。
那么综上所述,我们来通过一张图,了解一下属性编辑器的注册和使用操作相关的类关系图:
在上面的例子中,我们自定义了一个属性编辑器DatePropertyEditor
,其实Spring也内置了自己的属性编辑器ResourceEditorRegistrar。
在ResourceEditorRegistrar的registerCustomEditors(...)
方法中,提供了Spring默认配置的所有属性编辑器集合。如下所示:
在doRegisterEditor(...)
中,我们发现该方法的内部实现与自定义属性编辑器实现方式基本一样,即:通过调用registry.registerCustomEditor(requiredType, editor)
方法来注册属性编辑器。如下所示:
此处我们再提及一点,就是在PropertyEditorRegistrySupport类的createDefaultEditors()
方法中,包含了Spring给我们提供的一系列默认编辑器。具体如下所示:
private void createDefaultEditors() {
this.defaultEditors = new HashMap<>(64);
// Simple editors, without parameterization capabilities.
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.
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);
}
}
下面我们继续来分析prepareBeanFactory(...)
方法中的源码,如下所示:
【解释】在上面的源码红框中,只是将ApplicationContextAwareProcessor实例对象添加到了beanFactory的后置处理器集合中(即:
List
)。beanPostProcessors
那既然ApplicationContextAwareProcessor是后置处理器,那它必然就已经实现了BeanPostProcessor
接口。那么问题来了,后置处理器会在什么时候被Spring调用呢? 这个问题在前面章节的 bean实例化 过程中其实已经介绍过了,我们再来回顾一下。请见下图所示:
【解释】在bean实例化的时候,也就是在Spring调用init-method方法的前后,会分别调用所有实现了BeanPostProcessor接口的实现类的
postProcessBeforeInitialization(...)
方法和postProcessAfterInitialization(...)
方法。那么,下面我们就来看一下ApplicationContextAwareProcessor是如何自定义这两个方法的具体逻辑的。
ApplicationContextAwareProcessor的postProcessAfterInitialization(...)
方法没有做特殊逻辑处理,采用的就是它父接口BeanPostProcessor中默认的方法实现。源码如下所示:
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
ApplicationContextAwareProcessor的postProcessBeforeInitialization(...)
方法做了自定义的实现,源码如下所示:
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 只针对如下7种xxxAware进行特殊处理
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
bean instanceof ApplicationStartupAware)) return bean;
... ...
invokeAwareInterfaces(bean); // 为7种xxxAware设置对应的资源
... ...
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);
}
【解释】通过上面的源码,我们可以发现,在后置处理方法中,只是针对7种
Aware
实现设置了它们所需的资源。
我们继续来分析prepareBeanFactory(...)
方法中如下红框的内容。在4.3中我们当通过调用ApplicationContextAwareProcessor类的invokeAwareInterfaces()
方法之后,7种xxxAware类型bean就都已经处理完毕了,那么下面的依赖注入操作就不需要再处理这些xxxAware类了。所以在如下红框种就对这7种Aware类执行了忽略依赖操作。
下面我们再来继续分析prepareBeanFactory(...)
方法中如下红框的内容。这部分内容是,当注册了依赖解析后,例如当注册了对BeanFactory.class的解析依赖后,当bean的属性注入的时候,一旦检测到属性为BeanFactory类型便会将beanFactory的实例注入进去。
下面我们来分析refresh()
方法中的invokeBeanFactoryPostProcessors(beanFactory)
这段代码的含义之前,通过方法名称,我们可以猜到这段方法是用来处理BeanFactoryPostProcessor的,那么 它具体是做什么的呢? 请见如下源码所示:
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
【解释】
BeanFactoryPostProcessor
接口跟BeanPostProcessor
类似,都可以对bean的定义(即:配置的元数据)进行处理。也就是说,Spring允许BeanFactoryPostProcessor在容器实际实例化任何其他的bean之前读取配置元数据,并进行修改。如果配置多个BeanFactoryPostProcessor
,可以通过实现Ordered
接口来控制执行次序。
如果你想改变实际的bean实例,那么最好使用BeanPostProcessor。因为BeanFactoryPostProcessor的作用域范围是容器级别的。它只和你所使用的容器有关。它不会对定义在另一个容器中的bean进行后置处理。
那么,我们先不着急解析invokeBeanFactoryPostProcessors(beanFactory)
这段源码的具体逻辑,我们先插播一条“娱乐新闻”,即:如何去使用BeanFactoryPostProcessor
?
在某个路径下创建一个配置文件,我们以prop/common.properties
为例,在该文件内配置相应的属性值。
然后创建message的Bean配置信息,变量引用:${message.msg}
。表明在其他的配置文件中指定了message.msg
的值。那到底是哪个配置文件呢?我们创建PropertySourcesPlaceholderConfigurer的Bean配置信息。通过locations
属性,来指定配置文件所在路径。
从IOC中获取message的bean实例对象,然后输出msg的值。
在上面的演示中,我们可以看到虽然在配置PropertySourcesPlaceholderConfigurer
的Bean时指定了common.properties
的文件路径,但是这个文件是什么时候被加载解析的呢? 答案是:PropertySourcesPlaceholderConfigurer其实就是一种BeanFactoryPostProcessor,那么当Spring加载任何实现了这个接口的bean的配置时,都会在bean工厂载入所有bean的配置之后执行postProcessBeanFactory(beanFactory)
方法。类的继承关系图请见下图所示:
本节开篇就说了,BeanFactoryPostProcessor接口只有一个方法,即:postProcessBeanFactory(beanFactory)
,那么下面我们来看一下PropertySourcesPlaceholderConfigurer类是怎么实现的这个方法:
那么当配置文件信息被加载到了内存中后,就可以通过message.msg
所配置的“Hello World!”值来替换${message.msg}
了。此处替换流程暂且不深究。下面我们来看看如何自己实现一个BeanFactoryPostProcessor。
实现接口BeanFactoryPostProcessor
,创建自定义处理类。在postProcessBeanFactory(beanFactory)
方法中实现垃圾话过滤逻辑。需要注意的是,这个过滤垃圾话的作用域是针对容器内所有的bean的。
配置Bean,设置需要过滤的垃圾话列表。
获取allMessage
的bean实例,验证msg
中的垃圾话是否被过滤掉了。
通过上面的示例,我们基本了解到了BeanFactoryPostProcessor
是如何使用的。那么,下面我们还是回到refresh()
方法中,看一下invokeBeanFactoryPostProcessors(beanFactory)
这段代码的具体实现逻辑:
invokeBeanFactoryPostProcessors(beanFactory)
方法的源码如下所示:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 激活BeanFactoryPostProcessor操作
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null
&& beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
激活的实际逻辑代码就在invokeBeanFactoryPostProcessors(...)
方法中,里面逻辑很多,我们先看这个方法的源码和注释,然后我们在下面内容中,抽取重要的内容再详细的讨论。
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory,
List beanFactoryPostProcessors) {
Set processedBeans = new HashSet<>(); // 用于存储已经处理过的处理器名称
/** 步骤1:对BeanDefinitionRegistry类型进行处理,包括【硬编码】+【配置方式】 */
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List regularPostProcessors = new ArrayList<>(); // 通过【硬编码】注册的BeanFactoryPostProcessor
List registryProcessors = new ArrayList<>(); // 通过【硬编码】注册的BeanDefinitionRegistryPostProcessor
/** 步骤1.1:遍历所有通过【硬编码】设置的BeanFactoryPostProcessor,按类型执行“分堆”操作,调用其postProcessBeanDefinitionRegistry(registry)方法 */
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry); // BeanDefinitionRegistryPostProcessor接口中的方法,对BeanDefinitionRegistry执行后置处理
registryProcessors.add(registryProcessor); // 通过【硬编码】注册的BeanDefinitionRegistryPostProcessor,会被放到registryProcessors中
} else {
regularPostProcessors.add(postProcessor); // 通过【硬编码】注册的其它BeanFactoryPostProcessor,会被放到regularPostProcessors中
}
}
/** 步骤1.2:处理所有通过【配置方式】注册且实现了”PriorityOrdered接口“的BeanDefinitionRegistryPostProcessor实例集合,调用其postProcessBeanDefinitionRegistry(registry)方法 */
List currentRegistryProcessors = new ArrayList<>();
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { // 如果实现了PriorityOrdered接口,则进行排序
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory); // 排序
registryProcessors.addAll(currentRegistryProcessors); // 合并【硬编码】和【配置方式(且实现了PriorityOrdered接口)】的BeanDefinitionRegistryPostProcessor集合
// 调用所有currentRegistryProcessors实例的postProcessBeanDefinitionRegistry(registry)方法,实现对registry的后置处理
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
/** 步骤1.3:处理所有通过【配置方式】注册且实现了”Ordered接口“的BeanDefinitionRegistryPostProcessor实例集合,调用其postProcessBeanDefinitionRegistry(registry)方法 */
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { // 如果实现了Ordered接口,则进行排序
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory); // 排序
registryProcessors.addAll(currentRegistryProcessors); // 合并【硬编码】和【配置方式(且实现了Ordered接口)】的BeanDefinitionRegistryPostProcessor集合
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
/** 步骤1.4:处理所有通过【配置方式】注册且实现了BeanDefinitionRegistryPostProcessor实例集合(排除实现Ordered接口和PriorityOrdered接口),调用其postProcessBeanDefinitionRegistry(registry)方法 */
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();
}
/** 步骤1.5:处理BeanDefinitionRegistryPostProcessor实例集合和BeanFactoryPostProcessor实例集合,调用其postProcessBeanFactory(beanFactory)方法 */
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
/** 步骤2:对ConfigurableListableBeanFactory而非BeanDefinitionRegistry类型进行处理【硬编码】+【配置方式】 ,调用其postProcessBeanFactory(beanFactory)方法*/
else {
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
List priorityOrderedPostProcessors = new ArrayList<>();
List orderedPostProcessorNames = new ArrayList<>();
List 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)) // 如果实现了PriorityOrdered接口,则进行排序
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) // 如果实现了Ordered接口,则进行排序
orderedPostProcessorNames.add(ppName);
else
nonOrderedPostProcessorNames.add(ppName); // 否则,不排序了
}
/** 步骤3:对ConfigurableListableBeanFactory类型并且实现了”PriorityOrdered接口“的进行处理【配置方式】 ,调用其postProcessBeanFactory(beanFactory)方法*/
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
List orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
/** 步骤4:对ConfigurableListableBeanFactory类型并且实现了”Ordered接口“的进行处理【配置方式】 ,调用其postProcessBeanFactory(beanFactory)方法*/
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
List nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
/** 步骤5:对ConfigurableListableBeanFactory类型并且没有实现(PriorityOrdered接口或Ordered接口)进行处理【配置方式】 ,调用其postProcessBeanFactory(beanFactory)方法*/
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
beanFactory.clearMetadataCache();
}
通过上面的源码和源码注释,我们可以看到,其实就是针对两种情况进行分别的后置处理:
【情况1】一个类实现了ConfigurableListableBeanFactory接口 + BeanDefinitionRegistry接口
【情况2】一个类仅实现了ConfigurableListableBeanFactory接口
而对于后置处理器来说,有如下对应的处理关系:
【针对BeanDefinitionRegistry接口】我们采用BeanDefinitionRegistryPostProcessor后置处理器进行增强操作。
【针对ConfigurableListableBeanFactory接口】我们采用BeanFactoryPostProcessor后置处理器进行增强操作。
而由于BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor,所以要区别处理:
找出实现了BeanDefinitionRegistry接口 + ConfigurableListableBeanFactory接口的bean
【步骤1】调用“
硬编码
”设置的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry(registry)
方法进行增强;
【步骤2】调用“配置方式
”设置的BeanDefinitionRegistryPostProcessor并实现了PriorityOrdered接口的postProcessBeanDefinitionRegistry(registry)
方法进行增强;
【步骤3】调用“配置方式
”设置的BeanDefinitionRegistryPostProcessor并实现了Ordered接口的postProcessBeanDefinitionRegistry(registry)
方法进行增强;
【步骤4】调用“配置方式
”设置的BeanDefinitionRegistryPostProcessor没有实现排序接口的postProcessBeanDefinitionRegistry(registry)
方法进行增强;
【步骤5】调用“硬编码
”BeanDefinitionRegistryPostProcessor的postProcessBeanFactory(beanFactory)
方法进行增强;
【步骤6】调用“硬编码
”BeanFactoryPostProcessor的postProcessBeanFactory(beanFactory)
方法进行增强;
找出仅仅实现了ConfigurableListableBeanFactory接口的bean
【步骤1】调用“
硬编码
”设置BeanFactoryPostProcessor的postProcessBeanFactory(beanFactory)
方法进行增强;
【步骤2】调用“配置方式
”设置的BeanFactoryPostProcessor并实现了PriorityOrdered接口的postProcessBeanFactory(beanFactory)
方法进行增强;
【步骤3】调用“配置方式
”设置的BeanFactoryPostProcessor并实现了Ordered接口的postProcessBeanFactory(beanFactory)
方法进行增强;
【步骤4】调用“配置方式
”设置的BeanFactoryPostProcessor没有实现排序接口的postProcessBeanFactory(beanFactory)
方法进行增强;
那么,什么样的类即实现BeanDefinitionRegistry接口又实现ConfigurableListableBeanFactory接口呢? 我们以DefaultListableBeanFactory为例,它就是既实现了ConfigurableListableBeanFactory
接口,也实现了BeanDefinitionRegistry
接口。如下所示:
那么 上面所说的【硬编码】,又是从哪里写入的呢? 我们可以看到在 AbstractApplicationContext 类中有addBeanFactoryPostProcessor(postProcessor)
方法,通过它,我们就可以采用硬编码的方式添加PostProcessor了。
为了更便于大家对整个流程的理解,如下我提供了针对整体处理流程的图解。
针对实现了BeanDefinitionRegistry接口 + ConfigurableListableBeanFactory接口 的bean,调用BeanDefinitionRegistryPostProcessor 类的postProcessBeanDefinitionRegistry(registry)
方法的后置处理
针对实现了BeanDefinitionRegistry接口 + ConfigurableListableBeanFactory接口 的bean,调用 BeanFactoryPostProcessor 类的postProcessBeanFactory(beanFactory)
方法的后置处理
针对仅仅实现了ConfigurableListableBeanFactory接口的bean,调用BeanFactoryPostProcessor类的postProcessBeanFactory(beanFactory)
方法的后置处理
创建一个BeanPostProcessor
的实现类——MuseBeanPostProcessor.java
在oldbean.xml
配置文件中注册MuseBeanPostProcessor后置处理器。
启动项目,我们发现当使用ApplicationContext加载bean的时候,就可以调用我们创建的后置处理器;但是如果使用XmlBeanFactory加载bean,却无法调用我们创建的后置处理器。
其实这也印证了ApplicationContext是BeanFactory的加强版本,即:Plus版本。在Spring中,其实绝大部分的功能都是通过后置处理器的方式进行扩展的,而BeanFactory其实只是初始化IOC容器了,并没有实现后置处理器的自动注册功能。
而ApplicationContext实现了自动添加后置处理器的能力,所以才会通过调用applicationContext.getBean("allMessage")
的方式输出了“-------allMessage---------”,而通过beanFactory.getBean("allMessage")
的方式却没有输出。
我们了解了怎样去使用BeanPostProcessor
之后,下面我们来看一下涉及到注册BeanPostProcessor
的逻辑代码,如下所示:
如下是最核心的BeanPostProcessor方法,这里面的逻辑与BeanFactoryPostProcessor类似,请见如下源码和注释:
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// BeanPostProcessorChecker是一个用于检查操作的后置处理器,即:当Spring配置中的后处理器还没有被注册就已经开始了bean的初始化是,那么Checker就会打印提示信息日志
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
List priorityOrderedPostProcessors = new ArrayList<>();
List internalPostProcessors = new ArrayList<>();
List orderedPostProcessorNames = new ArrayList<>();
List nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { // 存储实现了PriorityOrdered接口的后置处理器
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor)
internalPostProcessors.add(pp); // 存储实现了PriorityOrdered接口并且是MergedBeanDefinitionPostProcessor类型后置处理器
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class))
orderedPostProcessorNames.add(ppName); // 存储实现了Ordered接口的后置处理器
else
nonOrderedPostProcessorNames.add(ppName); // 存储未实现排序接口的后置处理器
}
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
List 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); // 存储实现了Ordered接口并且是MergedBeanDefinitionPostProcessor类型后置处理器
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
List 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); // 存储没有实现排序接口并且是MergedBeanDefinitionPostProcessor类型后置处理器
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// 注册MergedBeanDefinitionPostProcessor类型后置处理器
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
【步骤1】针对实现了
PriorityOrdered
接口的BeanPostProcessor后置处理器执行排序和注册操作。
【步骤2】针对实现了Ordered
接口的BeanPostProcessor后置处理器执行排序和注册操作。
【步骤3】针对没有实现排序接口的BeanPostProcessor后置处理器执行注册操作。
【步骤4】针对MergedBeanDefinitionPostProcessor类型的后置处理器执行注册操作。
在调用registerBeanPostProcessors(...)
方法时,不用担心重复注册问题,因为都是先执行remove再执行add的,如下所示:
Spring国际化是根据客户端的系统语言类型返回对应的界面,这个便是所谓的i18n国际化(internationalization
)。
国际化信息也称之为本地化信息,需要两个条件来最终决定:
【条件1】语言类型(eg:中文)
【条件2】国家/地区的类型(ge:中国大陆、中国台湾、中国香港、新加坡、马来西亚……)
在JDK中,提供了java.util.Locale类用来支持国际化信息,它提供了如下使用方式:
【方式1】指定语言和国家/地区——
new Locale("zh", "CN")
或Locale.CHINA
【方式2】指定语言——new Locale("zh")
或Locale.CHINESE
【方式3】根据操作系统默认语言设置——Locale.getDefault()
MessageSource是负责国际化信息的接口,它有如下几个重要实现类:
ResourceBundleMessageSource:允许通过资源名加载国际化资源。
ReloadableResourceBundleMessageSource:与ResourceBundleMessageSource
功能相似,额外提供定时刷新功能,不用重启系统,即可更新资源信息。
StaticMessageSource:主要用于程序测试,允许通过编程的方式提供国际化信息。
DelegatingMessageSource:为方便操作MessageSource
的代理类。
创建i18n_zh.properties
文件,里面添加“hello=你好!世界!”,然后通过 native2ascii 将其转化为utf8的ASCII编码文件。
创建i18n_en.properties
文件,里面添加“hello=Hello World!”,然后将i18n_zh.properties
和i18n_en.properties
都放入到muse文件夹下。如下所示:
在配置文件oldbean.xml
中配置国际化支持,其中bean id必须是“messageSource”,否则就会报NoSuchMessageException
异常
执行测试代码:
了解了怎么使用国际化信息之后,我们现在来看一下初始化国际化资源的代码逻辑,如下图红框所示:
那么,在initMessageSource()
方法中,通过判断是自定义国际化资源还是默认国际化资源,创建MessageSource
实现类,然后赋值给AbstractApplicationContext的全局变量messageSource。
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 如果需要用户自定义国际化资源,则需要创建一个bean的id必须是“messageSource”(硬编码)的bean
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
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());
}
}
}
// 否则,使用DelegatingMessageSource,一般后续通过调用getMessage方法返回国际化资源
else {
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms; // 赋值给全局变量messageSource
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
}
}
protected MessageSource getInternalParentMessageSource() {
return (getParent() instanceof AbstractApplicationContext ?
((AbstractApplicationContext) getParent()).messageSource : getParent());
}
public ApplicationContext getParent() {
return this.parent;
}
在使用时,我们通过调用applicationContext.getMessage("hello", null, Locale.US)
来获取国际化信息,那么我们看一下getMessage(...)
方法的源码是怎么处理的:
public String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {
return getMessageSource().getMessage(code, args, locale);
}
private MessageSource getMessageSource() throws IllegalStateException {
if (this.messageSource == null)
throw new IllegalStateException("MessageSource not initialized - call 'refresh' before accessing messages via the context: " + this);
return this.messageSource; // 就是从全局messageSource中获取的国际化资源
}
首先,继承ApplicationEvent
,实现自定义ApplicationEvent——MuseApplicationEvent:
其次,实现ApplicationListener
接口,实现自定义ApplicationListener——MuseApplicationListener:
将自定义应用监听器MuseApplicationListener注册倒IOC中:
测试发布一个MuseApplicationEvent类型的事件,查看控制台输出内容:
好了,我们通过刚刚的示例,了解到了如何使用应用事件发起广播,那么下面我们就来看一下源码中如何进行初始化操作的,在下图refresh()
方法的红框中:
我们再来看initApplicationEventMulticaster()
方法的具体处理逻辑:
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 如果用户【自定义】了EventMulticaster,则向Spring中注册用户自定义的事件广播器
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
}
// 如果用户【没有自定义】EventMulticaster,则向Spring中注册默认的SimpleApplicationEventMulticaster广播器
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}
上面的代码逻辑也是比较简单清晰的,就执行了两个判断逻辑:
【判断1】如果用户自定义
了EventMulticaster,则向Spring中注册用户自定义的事件广播器。
【判断2】如果用户没有自定义
EventMulticaster,则向Spring中注册默认的SimpleApplicationEventMulticaster广播器。
那么,我们在看一下SimpleApplicationEventMulticaster中是怎么处理广播事件的:
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
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); // 采用串行方式执行广播操作
}
}
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); // 触发广播监听行为
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event); // 发送监听事件
}catch (ClassCastException ex) {...}
}
从上面的代码中,我们可以看出核心的逻辑就是两个步骤:
【步骤1】通过getApplicationListeners(event, type)
方法获得所有的应用监听器列表。
【步骤2】遍历调用每一个ApplicationListener的onApplicationEvent(event)
方法来发送监听事件。
需要注意的一点就是,当产生Spring监听事件的时候,对于每一个监听器来说,其实他们都可以获得所有产生的监听事件,那么具体处理哪一种类型的监听事件,可以在监听器中进行逻辑处理(如:上面8.1使用示例中的MuseApplicationListener实现方式)。当然,我们也可以通过使用泛型来约束处理的监听事件类型。如下图所示,那么MuseApplicationListener
就只能处理MuseApplicationEvent
类型的事件了。
注册监听器的理解代码如下所示:
下面我们再来详细看一下registerListeners()
方法的具体逻辑:
protected void registerListeners() {
/** 添加以【硬编码】方式注册的监听器 */
for (ApplicationListener> listener : getApplicationListeners())
getApplicationEventMulticaster().addApplicationListener(listener);
/** 添加以【配置文件】方式注册的监听器 */
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames)
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
/** 发送在多播设置之前发布的ApplicationEvent事件 */
Set earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess))
for (ApplicationEvent earlyEvent : earlyEventsToProcess)
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
注册监听器的方法也比较简单清晰,它一共做到了如下3个步骤:
【步骤1】添加以硬编码
方式注册的监听器
【步骤2】添加以配置文件
方式注册的监听器
【步骤3】发送在多播设置之前发布的ApplicationEvent
事件
此处涉及到的就是我们完成了BeanFactory初始化工作之后的收尾工作了,包含:
【步骤1】为上下文添加ConversionService
【步骤2】为上下文添加EmbeddedValueResolver(嵌入值解析器)
【步骤3】初始化LoadTimeWeaverware类型的Bean
【步骤4】停止使用临时ClassLoader进行类型匹配
【步骤5】冻结配置
【步骤6】实例化所有剩余的(非惰性初始化)单例
我们来看一下负责这部分逻辑的代码:
具体的逻辑处理就是在finishBeanFactoryInitialization(beanFactory)
的方法中,如下所示:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
/** 步骤1:为上下文初始化ConversionService */
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && // 是否存在名称为“conversionService”并且类型是ConversionService的Bean
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class))
beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
/** 步骤2:如果没有设置EmbeddedValueResolver(嵌入值解析器),则默认添加一个StringValueResolver */
if (!beanFactory.hasEmbeddedValueResolver())
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
/** 步骤3:尽早初始化LoadTimeWeaverware类型的Bean,以便尽早注册其转换器 */
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames)
getBean(weaverAwareName);
beanFactory.setTempClassLoader(null); // 停止使用临时ClassLoader进行类型匹配
beanFactory.freezeConfiguration(); // 冻结配置
beanFactory.preInstantiateSingletons(); // 实例化所有剩余的(非惰性初始化)单例
}
冻结所有配置
public void freezeConfiguration() {
this.configurationFrozen = true; // 开启配置冻结开关
this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
}
初始化非延迟加载单例
public void preInstantiateSingletons() throws BeansException {
List beanNames = new ArrayList<>(this.beanDefinitionNames);
/** 步骤1:初始化所有非惰性单例bean */
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 针对FactoryBean创建bean
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) ((SmartFactoryBean>) factory)::isEagerInit, getAccessControlContext());
else
isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean>) factory).isEagerInit());
if (isEagerInit) // 对于配置了【非惰性加载】的bean执行创建操作
getBean(beanName);
}
}
// 针对非FactoryBean创建bean
else getBean(beanName);
}
}
/** 步骤2:对于配置了SmartInitializingSingleton的Bean,触发初始化后回调(post-initialization callback)*/
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
// 针对SmartInitializingSingleton类型触发初始化后回调,即:afterSingletonsInstantiated
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null)
AccessController.doPrivileged((PrivilegedAction
在上面代码中,总共执行了如下两个步骤:
【步骤1】步骤1:初始化所有非惰性(isEagerInit)单例bean。即:针对FactoryBean
类型创建bean 和 针对其他类型
创建bean;
【步骤2】对于配置了SmartInitializingSingleton的Bean,触发初始化后回调,即:调用afterSingletonsInstantiated()
方法;
最后这部分,我们来看一下finishRefresh()
方法的逻辑代码:
在finishRefresh()
方法中,主要就是针对Lifecycle接口进行处理,该接口主要包含如下两个重要方法:
start() :Spring启动的时候,调用该方法开始生命周期;
stop() :Spring关闭的时候,调用该方法结束生命周期;
那么下面我们来看一下在finishRefresh()
方法中,它是如何实现这个功能的:
protected void finishRefresh() {
clearResourceCaches(); // 仅执行清除缓存操作:resourceCaches.clear()
initLifecycleProcessor(); // 初始化生命周期处理器
getLifecycleProcessor().onRefresh(); // 启动所有实现了Lifecycle接口的bean
publishEvent(new ContextRefreshedEvent(this)); // 发布上下文已刷新的事件
if (!NativeDetector.inNativeImage()) // 判断是不是在GraalVM虚拟机上运行
LiveBeansView.registerApplicationContext(this);
}
初始化生命周期处理器——LifecycleProcessor
protected void initLifecycleProcessor() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
/** 步骤1:如果存在名字是“lifecycleProcessor”的生命周期处理器,则将其赋值给全局变量lifecycleProcessor */
if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
this.lifecycleProcessor = beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
/** 步骤2:如果不存在,则创建默认的生命周期处理器——DefaultLifecycleProcessor,并赋值给全局变量lifecycleProcessor */
else {
DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
defaultProcessor.setBeanFactory(beanFactory);
this.lifecycleProcessor = defaultProcessor;
beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
}
}
通过调用onRefresh()
方法来启动所有实现了Lifecycle接口的bean
public void onRefresh() {
startBeans(true); // 启动所有实现了Lifecycle接口的bean
this.running = true;
}
private void startBeans(boolean autoStartupOnly) {
Map lifecycleBeans = getLifecycleBeans(); // 获得所有Lifecycle集合
Map phases = new TreeMap<>();
/** 步骤1:如果autoStartupOnly是false,或者是SmartLifecycle类型的bean,并且其内部方法isAutoStartup()返回了true,则会保存到phase中 */
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);
}
});
/** 步骤2:如果phase中存在待启动的LifecycleGroup,则调用每一个start()方法 */
if (!phases.isEmpty())
phases.values().forEach(LifecycleGroup::start); // 调用LifecycleGroup的start()方法
}
最后我们发现,会调用到DefaultLifecycleProcessor的内部类LifecycleGroup的start()
方法;然后在doStart()
方法中最终调用了每一个实现了Lifecycle接口的子类的start()
方法。
public void start() {
if (this.members.isEmpty()) return;
Collections.sort(this.members);
for (LifecycleGroupMember member : this.members)
doStart(this.lifecycleBeans, member.name, this.autoStartupOnly); // 在Spring中,真正执行某个逻辑都是以do开头的
}
private void doStart(Map lifecycleBeans, String beanName, boolean autoStartupOnly) {
Lifecycle bean = lifecycleBeans.remove(beanName);
if (bean != null && bean != this) {
String[] dependenciesForBean = getBeanFactory().getDependenciesForBean(beanName);
for (String dependency : dependenciesForBean)
doStart(lifecycleBeans, dependency, autoStartupOnly); // 如果有嵌套,则通过递归处理
if (!bean.isRunning() && (!autoStartupOnly || !(bean instanceof SmartLifecycle) || ((SmartLifecycle) bean).isAutoStartup())) {
try {
bean.start(); // 调用Lifecycle实现类的start()方法触发生命周期开始操作
} catch (Throwable ex) {...}
}
}
}
今天的文章内容就这些了:
写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享 。