Container function extension and refresh method analysis
In the previous article, we learned about the bean loading process in Spring, and have been using the BeanFactory interface and its default implementation class XmlBeanFactory. Another interface ApplicationContext is also provided in Spring to extend the existing functions in BeanFactory.
First of all, both BeanFactory and ApplicationContext are used to load beans, but in contrast, ApplicationContext provides more extension functions, and ApplicationContext contains all the functions of BeanFactory. Usually we will use ApplicationContext first.
Let's take a look at what functions the ApplicationContext has?
First look at the difference in spelling.
Load XML using BeanFactory
final BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
Load XML using ApplicationContext
final ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
We start to click on the constructor of ClassPathXmlApplicationContext and analyze it.
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
In the ClassPathXmlApplicationContext, the configuration file path can be passed in in the form of an array, and the parsing and function implementation are implemented in the refresh()
method.
set configuration path
public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
This function mainly resolves the given path array. If the array contains special symbols, such as ${var}, then the resolvePath method will search for the matching system variable and replace it.
extensions
After setting the path, you can parse the file and implement various functions. It can be said that the refresh method contains almost all the functions provided in the ApplicationContext, and the logic of this function is also very clear. It is easy to analyze the corresponding level and logic.
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备刷新的上下文环境,包括设置启动时间,是否激活标识位
// 初始化属性源(property source)配置
prepareRefresh();
// 初始化BeanFactory 并进行xml文件读取
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 对BeanFactory进行各种功能填充
prepareBeanFactory(beanFactory);
try {
// 子类覆盖方法做额外的处理
postProcessBeanFactory(beanFactory);
// 激活各种BeanFactory处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截bean创建的bean处理器,只是注册,具体调用在getBean中
registerBeanPostProcessors(beanFactory);
// 为上下文初始化Message源,国际化处理
initMessageSource();
// 初始化应用消息广播器,并放入applicationEventMulticaster bean中
initApplicationEventMulticaster();
// 留给子类来初始化其他的bean
onRefresh();
// 在所有注册的bean中查找Listener bean,注册到消息广播器中
registerListeners();
// 初始化剩下的单例bean (非惰性)
finishBeanFactoryInitialization(beanFactory);
//完成刷新过程,通知生命周期处理器LifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
destroyBeans();
// 重置活动标志
cancelRefresh(ex);
throw ex;
}
finally {
//重置公共缓存
resetCommonCaches();
}
}
}
We summarize the steps of initialization.
- Preparations before initialization, such as preparing and verifying system properties or environment variables
- Initialize the BeanFactory and read the XML file. We said before that ClassPathXmlApplicationContext contains all the features provided by BeanFactory, then in this step, the configuration file reading and parsing and other functions in BeanFactory will be reused. After this step, ClassPathXmlApplicationContext already contains the functions provided by BeanFactory. That is, you can extract and other operations on the bean
- Fill the BeanFactory with various functions
- Subclasses override methods to do additional processing. Mainly used for further expansion of our business
- Activate various BeanFactory processors
- Register the bena processor that intercepts bean creation, here is just registration, the real call is in getBean
- Initialize the Message source for the context and internationalize the message body in different languages
- Initialize the application message broadcaster and put it in the "applicationEventMulticaster" bean
- Leave it to subclasses to initialize other beans
- Find the listener bean in all registered beans and register with the message broadcaster
- Initialize the remaining singleton (non-lazy)
- Complete the refresh process, notify the lifecycle processor of the refresh process, and issue a ContextRefreshEvent to notify others
Environmental preparation
The prepareRefresh method mainly does some preparatory work, such as initialization and verification of system properties and environment variables.
-
initPropertySources
There is an empty implementation in this method, which is mainly used for us to rewrite the method according to our needs, and perform personalized attribute processing and setting in the method.
protected void initPropertySources() {
// For subclasses: do nothing by default.
}
-
validateRequiredProperties
This method mainly verifies attributes. By default nothing is checked. After we inherit the ClassPathXmlApplicationContext class and rewrite the initPropertySources method, the relevant verification will be performed.
Load BeanFactory
The obtainFreshBeanFactory method is mainly used to obtain the BeanFactory. I just said that the ApplicationContext has all the functions of the BeanFactory. This method is where the BeanFactory is implemented. That is to say, after calling this method, the applicationContext has the function of the BeanFactory.
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//初始化BeanFactory,并进行XML文件读取,将得到的BeanFactory记录到当前实体属性中
refreshBeanFactory();
//返回当前实体的beanFactory属性
return getBeanFactory();
}
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
We enter the AbstractRefreshableApplicationContext#refreshBeanFactory()
method.
protected final void refreshBeanFactory() throws BeansException {
//判断是否存在beanFactory
if (hasBeanFactory()) {
//销毁所有单例
destroyBeans();
//重置beanFactory
closeBeanFactory();
}
try {
//创建beanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
//设置序列化id
beanFactory.setSerializationId(getId());
//定制beanFactory,设置相关属性,包括是否允许覆盖同名称不同定义的对象以及循环依赖
customizeBeanFactory(beanFactory);
//初始化DocumentReader,进行XML读取和解析
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
To summarize the flow of this method:
- Create DefaultListableBeanFactory . The declaration method is:
BeanFactory bf = new XmlBeanFactory("beanFactoryTest.xml")
, where XmlBeanFactory inherits from DefaultListableBeanFactory and provides the reader property of XmlBeanDefinitionReader type, that is to say, DefaultListableBeanFactory is the basis of the container and must be instantiated first, here are the steps to instantiate DefaultListableBeanFactory - Specify serialization ID
- Custom BeanFactory
- Load BeanDefinition
- Use global variables to record BeanFactory class instances
Custom BeanFactory
First of all, let's understand the customizeBeanFactory method. This method is based on the basic container and adds the settings of whether to allow overwriting and whether to allow extension.
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
//如果不为空,设置beanFactory对象响应的属性,含义:是否允许覆盖同名称的不同定义的对象
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//如果属性不为空,设置给beanFactory对象相应属性,含义:是否允许bean之间存在循环依赖
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
Specifically, here is just a simple judgment. Where to set the properties, you can use subclasses to override them. E.g:
/**
* @author 神秘杰克
* 公众号: Java菜鸟程序员
* @date 2022/6/12
* @Description 自定义ClassPathXmlApplicationContext
*/
public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
@Override
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
super.setAllowBeanDefinitionOverriding(false);
super.setAllowCircularReferences(false);
super.customizeBeanFactory(beanFactory);
}
}
Load BeanDefinition
After initializing DefaultListableBeanFactory, we also need XmlBeanDefinitionReader to read XML files. The first thing to do in this step is to initialize XmlBeanDefinitionReader.
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//为指定beanFactory创建XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
//进行环境变量的设置
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//对beanDefinitionReader进行设置,可以覆盖
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
After initializing DefaultListableBeanFactory and XmlBeanDefinitionReader, we can read the configuration file. Finally, the BeanDefinitionHolder read by XmlBeanDefinitionReader will be registered in DefaultListableBeanFactory.
After this method, the variable beanFactory in the type DefaultListableBeanFactory already contains all the parsed configurations. The reading of configuration files has been covered in the previous article, so I will not repeat them here.
function extension
After we have finished parsing the configuration file, we then enter the prepareBeanFactory method.
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//设置beanFactory的ClassLoader为当前context的ClassLoader
beanFactory.setBeanClassLoader(getClassLoader());
//设置beanFactory的表达式语言处理
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
//为beanFactory增加了一个默认的propertyEditor,主要是对bean的属性等设置管理的一个工具
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
//添加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.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
//增加了ApplicationListenerDetector主要是检测bean是否实现了ApplicationListener接口
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
//增加对AspectJ的支持
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
//添加默认的系统环境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());
}
}
This method is mainly extended in several aspects:
- Added support for SpEL language
- Added support for property editor
- Added some built-in classes, such as EnvironmentAware, MessageSourceAware information injection
- Sets the interface for which the dependent function can be ignored
- Some fixed dependencies are registered
- Add AspectJ support
- Register related environment variables and properties in singleton mode
Postprocessing of BeanFactory
BeanFactory, as the basis of the container in Spring, is used to store all the loaded beans. In order to ensure the high scalability of the program, Spring has made a lot of extensions to the BeanFactory, such as PostProcessor, etc. are implemented here.
Activate the registered BeanFactoryPostProcessor
Before learning, let's first understand the usage of BeanFactoryPostProcessor. The BeanFactoryPostProcessor interface is similar to the BeanPostProcessor and can process bean definitions. That is, the Spring IOC container allows the BeanFactoryPostProcessor to read configuration metadata before the container instantiates any beans, and can modify it. Multiple BeanFactoryPostProcessors can be configured, and the execution order is controlled by implementing the Ordered interface to set "order".
It should be noted that if a BeanFactoryPostProcessor is defined in the container, it only performs post-processing on beans in this container. BeanFactoryPostProcessor does not post-process beans in other containers.
1.BeanFactoryPostProcessor的典型应用:PropertySourcesPlaceholderConfigurer
First let's take a look at the configuration file:
<bean id="hello" class="cn.jack.Hello">
<property name="msg">
<value>${bean.msg}</value>
</property>
</bean>
In it, we use the variable reference: ${bean.msg}, which is Spring's decentralized configuration, and we can configure the value of this property in the configuration file.
application.properties
bean.msg=hi
Then we configure the configuration file.
<bean id="helloHandler" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="locations">
<list>
<value>application.properties</value>
</list>
</property>
</bean>
At this time, we understand that we obtain our configuration information through PreferencesPlaceholderConfigurer. We can see that the class indirectly inherits the BeanFactoryPostProcessor interface.
When Spring loads any bean that implements this interface, the postProcessBeanFactory method is executed after the bean factory has loaded all bena's configuration. In the method, the three methods of mergeProperties, convertProperties, and processProperties are called successively to obtain the configuration, convert the obtained configuration to the appropriate type, and finally inform the BeanFactory of the configuration content.
It is by implementing BeanFactoryPostProcessor that the BeanFactory obtains configuration information before instantiating any beans, thus being able to correctly resolve variable references in the bean configuration file .
PropertySourcesPlaceholderConfigurer has replaced PropertyPlaceholderConfigurer because it aggregates Environment and multiple PropertySources. Therefore, it can control the priority and order of values, and also provides access methods, so it is not a problem to obtain them later.
2.使用自定义BeanFactoryPostProcessor
We implement a custom BeanFactoryPostProcessor ourselves to remove the function of attribute values that we don't want to display to show the creation and use of a custom BeanFactoryPostProcessor. For example, we block 'guapi' and 'shazi' in the bean definition.
<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 class="cn.jack.ObscenityRemovingBeanFactoryPostProcessor" id="customBeanFactoryPostProcessor">
<property name="obscenities">
<set>
<value>guapi</value>
<value>shazi</value>
</set>
</property>
</bean>
<bean class="cn.jack.SimpleBean" id="simpleBean">
<property name="userName" value="jack"/>
<property name="address" value="guapi"/>
<property name="email" value="shazi"/>
</bean>
</beans>
public class SimpleBean {
private String userName;
private String email;
private String address;
//getter setter
}
public class ObscenityRemovingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private final Set<String> obscenities;
public ObscenityRemovingBeanFactoryPostProcessor() {
this.obscenities = new HashSet<>();
}
/**
* 将所有bean 的参数中含有 obscenities 集合中的值进行屏蔽
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
final BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
StringValueResolver valueResolver = strVal -> {
if (isObscene(strVal)){
return "*****";
}
return strVal;
};
final BeanDefinitionVisitor beanDefinitionVisitor = new BeanDefinitionVisitor(valueResolver);
beanDefinitionVisitor.visitBeanDefinition(beanDefinition);
}
}
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());
}
}
}
Startup class:
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("beanFactory.xml");
SimpleBean simpleBean = (SimpleBean) ac.getBean("simpleBean");
System.out.println(simpleBean);
}
}
Output result:
SimpleBean{userName='jack', email='*****', address='*****'}
We use ObscenityRemovingBeanFactoryPostProcessor to mask out the properties we don't want to display.
Activate BeanFactoryPostProcessor
After we understand the usage of BeanFactoryPostProcessor, we can continue to go back to our refresh method and continue to study the source code.
Enter the invokeBeanFactoryPostProcessors method.
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 (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
We continue to enter the specific overloaded method invokeBeanFactoryPostProcessors.
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// 将已经执行过的BeanFactoryPostProcessor存储在processedBeans,防止重复执行
Set<String> processedBeans = new HashSet<>();
//对BeanDefinitionRegistry类型进行处理
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// 用来存放BeanFactoryPostProcessor对象
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
// 用来存放BeanDefinitionRegistryPostProcessor对象
// 方便统一执行实现了BeanDefinitionRegistryPostProcessor接口父类的方法
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// 处理外部定义的BeanFactoryPostProcessor,将BeanDefinitionRegistryPostProcessor与BeanFactoryPostProcessor区分开
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
//对于BeanDefinitionRegistryPostProcessor类型,需要先调用此方法,再添加到集合中
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
} else {
//记录常规BeanFactoryPostProcessor
regularPostProcessors.add(postProcessor);
}
}
//存放当前需要执行的BeanDefinitionRegistryPostProcessor
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// 调用实现 PriorityOrdered 的 BeanDefinitionRegistryPostProcessor。
// 获取所有实现了BeanDefinitionRegistryPostProcessor接口的类名
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
//判断当前类是否实现了PriorityOrdered接口
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//将BeanDefinitionRegistryPostProcessor类型存入currentRegistryProcessors中
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
// 提前存放到processedBeans,避免重复执行,但是此处还未执行
processedBeans.add(ppName);
}
}
//对currentRegistryProcessors集合中的BeanDefinitionRegistryPostProcessor类型进行排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
// 添加到registryProcessors集合,用于后续执行父接口的postProcessBeanFactory方法
registryProcessors.addAll(currentRegistryProcessors);
// 遍历集合,执行BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry()方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//执行完毕后清空该集合
currentRegistryProcessors.clear();
// 接着,调用实现 Ordered 的 BeanDefinitionRegistryPostProcessors
// 这里再次获取BeanDefinitionRegistryPostProcessor,是因为有可能在上面方法执行过程中添加了BeanDefinitionRegistryPostProcessor
// 而下面处理BeanFactoryPostProcessor的时候又不需要重复获取了是为什么呢?
// 因为添加BeanFactoryPostProcessor与BeanDefinitionRegistryPostProcessor只能在BeanDefinitionRegistryPostProcessor中添加,在BeanFactoryPostProcessor是无法添加的
for (String ppName : postProcessorNames) {
// 判断当前bean没有被执行过,并且实现了Ordered接口
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
//如果BeanFactory中没有该Bean则会去创建该Bean
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
//最后处理没有实现Ordered与PriorityOrdered接口的BeanDefinitionRegistryPostProcessor
boolean reiterate = true;
while (reiterate) {
reiterate = false;
// 再次获取BeanDefinitionRegistryPostProcessor
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
// 将本次要执行的BeanDefinitionRegistryPostProcessor存放到currentRegistryProcessors
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
//现在,调用到目前为止处理的所有处理器的 postProcessBeanFactory 回调。
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
} else {
// BeanFactory如果不归属于BeanDefinitionRegistry类型,则直接执行beanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// 用于存放实现了priorityOrdered接口的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
// 用于存放实现了ordered接口的BeanFactoryPostProcessor名称
List<String> orderedPostProcessorNames = new ArrayList<>();
// 用于存放无排序的BeanFactoryPostProcessor名称
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
// 如果已经执行过了,则不做处理
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
// 如果实现了PriorityOrdered 则添加
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
// 如果实现了Ordered 则添加
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
//如果没有排序则添加到指定集合
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 首先调用实现 PriorityOrdered 的 BeanFactoryPostProcessor。
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 然后调用实现 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);
// 最后调用其他没有排序的 BeanFactoryPostProcessor。
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// 清空缓存
beanFactory.clearMetadataCache();
}
Register BeanPostProcessor
After understanding the invocation of BeanFactoryPostProcessors, let's now understand the BeanPostProcessor, which is only a registration, not a call . The real call is made during the bean instantiation phase.
The automatic registration function of the post-processor is not implemented in the BeanFactory, so it cannot be used if it is not actively registered when it is called. But add active registration function in ApplicationContext.
For example, customize a post-processor like this:
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("===");
return null;
}
}
<bean class="cn.jack.MyInstantiationAwareBeanPostProcessor"/>
When using the ApplicationContext method to obtain the bean, "===" will be printed before the acquisition, and the bean loading in the BeanFactory method will not have this print.
This feature is implemented in registerBeanPostProcessors.
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
//获取所有实现BeanPostProcessor接口的类
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
//注册一个 BeanPostProcessorChecker,用来记录 bean 在 BeanPostProcessor 实例化时的信息
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
//区分实现不同接口的 BeanPostProcessors
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
//根据不同类型进行add
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);
}
}
// 排序后执行注册实现了 PriorityOrdered 的 BeanPostProcessors
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
//注册实现Ordered接口的BeanPostProcessors
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
//拿到ppName对应的BeanPostProcessor实例对象
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
//将ppName对应的BeanPostProcessor实例对象添加到orderedPostProcessors, 准备执行注册
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
//如果ppName对应的bean实例也实现了MergedBeanDefinitionPostProcessor接口,则添加到该集合中
internalPostProcessors.add(pp);
}
}
//对orderedPostProcessors进行排序并注册
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
//注册所有常规的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);
//注册所有mergedBeanDefinitionPostProcessor类型的BeanPostProcessor,并非重复注册
//在beanFactory.addBeanPostProcessor中会先移除已经存在的BeanPostProcessor
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// 添加ApplicationListener探测器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
Initialize message resources
The main function in initMessageSource is to extract the messageSource in the configuration file and record it in the Spring container, that is, the ApplicationContext. If the user does not set the resource file, get Spring's default configuration delegatingMessageSource.
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// Bean 的名称必须要是 messageSource
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) { //MESSAGE_SOURCE_BEAN_NAME = 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 {
//如果用户并没有定义配置文件,那么使用临时的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 + "]");
}
}
}
It is stipulated here that the resource file must be messageSource, otherwise the custom resource configuration will not be obtained.
Initialize ApplicationEventMulticaster
The implementation of the initApplicationEventMulticaster method is relatively simple, and there are two situations:
- If the user customizes the event broadcaster, then use the user-defined event broadcaster
- If the user does not have a custom event broadcaster, then use the default ApplicationEventMulticaster
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//判断容器中是否存在BeanDefinitionName为applicationEventMulticaster的bd,也就是自定义的事件监听多路广播器,必须实现ApplicationEventMulticaster接口
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() + "]");
}
}
}
Finally, as a broadcaster, it must be used to store the listener and call the listener when appropriate. Let's take a look at the default broadcaster implementation class SimpleApplicationEventMulticaster.
See the following method:
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);
}
}
}
It can be inferred that when a Spring event is generated, the multicastEvent of SimpleApplicationEventMulticaster will be used by default to broadcast the event, traverse all the listeners, and use the onApplicationEvent method in the listener to process the listener. For each listener, the generated event can actually be obtained, but whether to process it or not is determined by the event listener.
register listener
We have mentioned the listener repeatedly. Let's take a look at what logic operations Spring does when registering the listener?
protected void registerListeners() {
// 首先注册静态的指定的监听器,注册的是特殊的事件监听器,而不是配置中的bean
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 这里不会初始化FactoryBean,我们需要保留所有的普通bean
// 不会实例化这些bean,让后置处理器可以感知到它们
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 现在有了事件广播组,发布之前的应用事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
Just register some special listeners to the broadcast group. Those classes that implement the ApplicationListener interface in the bean configuration file have not been instantiated, so just save the name to the broadcast group at this time, and register these listeners to the broadcast group. The operations in the bean are done in the bean's post-processor, when the instantiation of the bean has been completed.
Initialize a non-lazy loaded singleton
Complete the initialization of the BeanFactory, including the settings of the ConversionService, configuration freezing, and initialization of non-lazy-loaded beans.
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 初始化此上下文的转换服务
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// 如果beanFactory之前没有注册解析器,则注册默认的解析器,例如${}解析成真正的属性:主要用于注解属性值的解析
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
//处理 @EnableLoadTimeWeaving 或 <context:load-time-weaver/> 标记的类
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
//临时类加载器设置为空
beanFactory.setTempClassLoader(null);
//冻结所有的bean定义,说明注册的bean定义将不被修改或者进一步处理
beanFactory.freezeConfiguration();
//初始化剩下的单例实例(非惰性)
beanFactory.preInstantiateSingletons();
}
First, let's understand the role provided by the ConversionService class.
1.ConversionService settings
Earlier we mentioned that you can use a custom type converter to convert the String type to Date, and Spring also provides the use of Converter for conversion.
2. Freeze configuration
Freeze all bean definitions, indicating that the registered bean definitions will not be modified or processed at any stage.
public void freezeConfiguration() {
this.configurationFrozen = true;
this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
}
3. Initialize lazy loading
The default behavior of the ApplicationContext implementation is to pre-instantiate all singleton beans at startup. Early instantiation also means that the ApplicationContext instance will create and configure all singleton beans as part of the initialization process, which is done in the preInstantiateSingletons method in the finishBeanFactoryInitialization method.
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
//创建beanDefinitionNames的副本beanNames用于后续的遍历,以允许init等方法注册新的bean定义
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
//遍历beanNames,触发所有非懒加载单例bean的初始化
for (String beanName : beanNames) {
//获取beanName对应的MergedBeanDefinition
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//bd对应的不是抽象类 && 并且是单例 && 并且不是懒加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//判断是否为FactoryBean
if (isFactoryBean(beanName)) {
//通过前缀&和beanName拿到Bean
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
//如果为FactoryBean
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
//判断这个FactoryBean是否希望急切的初始化
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
//如果希望急切的初始化,则通过beanName获取bean实例
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
//如果beanName对应的bean不是FactoryBean,只是普通Bean,通过beanName获取bean实例
getBean(beanName);
}
}
}
//遍历beanNames,触发所有SmartInitializingSingleton的后初始化回调
for (String beanName : beanNames) {
//拿到beanName对应的bean实例
Object singletonInstance = getSingleton(beanName);
//判断singletonInstance是否实现了SmartInitializingSingleton接口
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
//触发SmartInitializingSingleton实现类的afterSingletonsInstantiated方法
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
finishRefresh
The Lifecycle interface is provided in Spring, which contains start/stop methods. After implementing this interface, Spring will ensure that its start method is called at startup to start the declaration cycle, and when Spring shuts down, the stop method is called to end the declaration cycle. It is usually used to configure the background program, and it has been running after startup (such as MQ), and the finishRefresh method of the last step of the ApplicationContext is to achieve this function.
protected void finishRefresh() {
//清除资源缓存
clearResourceCaches();
//1.为此上下文初始化生命周期处理器
initLifecycleProcessor();
//2.首先将刷新完毕事件传播到生命周期处理器(触发isAutoStartup方法返回true的SmartLifecycle的start方法)
getLifecycleProcessor().onRefresh();
//3.推送上下文刷新完毕事件到相应的监听器
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
1. initLifecycleProcessor
When the ApplicationContext is started or stopped, it will update the state with the cycle of all declared beans through the LifecycleProcessor, and be initialized first before the LifecycleProcessor is used.
protected void initLifecycleProcessor() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//判断BeanFactory是否已经存在生命周期处理器(beanName=lifecycleProcessor)
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
DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
defaultProcessor.setBeanFactory(beanFactory);
this.lifecycleProcessor = defaultProcessor;
// 并将DefaultLifecycleProcessor作为默认的生命周期处理器,注册到BeanFactory中
beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
if (logger.isTraceEnabled()) {
logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +
"[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");
}
}
}
2.onRefresh
Start all beans that implement the Lifecycle interface
public void onRefresh() {
startBeans(true);
this.running = true;
}
private void startBeans(boolean autoStartupOnly) {
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<>();
lifecycleBeans.forEach((beanName, bean) -> {
if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
int phase = getPhase(bean);
LifecycleGroup group = phases.get(phase);
if (group == null) {
group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
phases.put(phase, group);
}
group.add(beanName, bean);
}
});
if (!phases.isEmpty()) {
List<Integer> keys = new ArrayList<>(phases.keySet());
Collections.sort(keys);
for (Integer key : keys) {
phases.get(key).start();
}
}
}
3.publishEvent
When the initialization of the ApplicationContext is completed, the ContextRefreshedEvent event should be issued through the publishing mechanism in Spring to ensure that the corresponding listener can do further logic processing.
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
//如有必要,将事件装饰为ApplicationEvent
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);
}
//通过parent发布事件
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
At this point, the refresh method is parsed. The next step is AOP.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。