0 前言
关于Spring容器启动过程的分析,本章节文章分为两篇文章进行叙述,第一篇主要介绍Spring中Bean的相关概念以及IoC容器类型;第二篇开始详细介绍IoC容器的启动过程。
上篇Spring原理与源码分析系列(二)- Spring IoC容器启动过程分析(上)已经介绍了介绍Spring中Bean的相关概念以及IoC容器类型。本篇主要详述IoC容器的启动过程。
四、Spring IoC容器实现过程
Spring IoC容器实现过程可分为两个阶段:
- 容器启动阶段
- Bean实例化阶段
下面来详细解释这两个过程。
1 容器启动阶段
容器启动阶段,主要是对象管理信息的收集。
除了直接代码的方式,一般是先读取和加载配置信息内容,
并将分析后的信息编组为BeanDefinition,
然后将保存了bean定义必要信息的BeanDefinition注册到BeanDefinitionRegistry中,这样启动工作就完成了。
(第一阶段:容器启动阶段)
BeanFactoryPostProcessor
在容器启动阶段,BeanFactoryPostProcessor接口允许我们在容器实例化相应对象之前,对注册到容器的BeanDefinition所保存的信息做相应的修改,比如修改其中bean定义的某些属性,把bean的scope从singleton改为prototype,也可以把property的值给修改掉,为bean定义增加其他信息等。
BeanFactoryPostProcessor是在Spring容器加载了bean的定义文件之后,在bean实例化之前执行的。
BeanFactoryPostProcessor接口定义如下:
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
接口方法的入参是ConfigurrableListableBeanFactory,使用该参数,可以获取到相关bean的定义信息.
使用的时候,我们可以自己实现BeanFactoryPostProcessor接口,然后修改Bean属性。
举个栗子:
(1)Bean:
package com.wgs.spring.beanfactorypostprocessor;
/**
* @author GenshenWang.nomico
* @date 2017/11/21.
*/
public class Staff {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
并为其注入属性值:
<bean id="staff" class="com.wgs.spring.beanfactorypostprocessor.Staff">
<property name="age" value="25"></property>
<property name="name" value="wgs"></property>
</bean>
(2)自己实现一个BeanFactoryPostProcessor,将Bean属性中的name原始值“wgs”改为“Jack Ma”。
package com.wgs.spring.beanfactorypostprocessor;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* @author GenshenWang.nomico
* @date 2017/11/21.
*/
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor{
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//BeanFactoryPostProcessor发生在读取Bean的BeanDefinition后,Bean实例化之前,所以获取的是BeanDefinition
BeanDefinition staffBeanDefinition = beanFactory.getBeanDefinition("staff");
//获取bean属性
MutablePropertyValues propertyValues = staffBeanDefinition.getPropertyValues();
if(propertyValues.contains("name")){
propertyValues.addPropertyValue("name", "Jack Ma");
}
}
}
(3)测试:
注释掉spirng.xml中的配置:
<bean id="myBeanFactoryPostProcessor" class="com.wgs.spring.beanfactorypostprocessor.MyBeanFactoryPostProcessor"></bean>
,输出的结果为”wgs”;
在spirng.xml加上<bean id="myBeanFactoryPostProcessor" class="com.wgs.spring.beanfactorypostprocessor.MyBeanFactoryPostProcessor"></bean>
,这样BeanFactoryPostProcessor就能起作用,使name的值“wgs”被修改为“Jack Ma”,所以输出的结果也为“Jack Ma”。
如果一个容器有多个实现BeanFactoryPostProcessor的接口,这时候就需要实现类实现org.springframework.core.Ordered
接口,设置order属性来保证自定义的BeanFactoryPostProcessor的实现类的执行顺序。
BeanFactoryPostProcessor接口有三个常用的实现类:
- org.springframework.beans.factory.config.PropertyPlaceholderConfigurer:允许我们在XML配置文件中使用占位符,并将这些占位符所代表的资源单独配置到简单的properties文件中来加载;
- org.springframework.beans.factory.config.PropertyOverrideConfigurer:可以通过占位符,来明确表明bean定义中的property与properties文件中的各项配置项之间的关系。
- org.springframework.beans.factory.config.CustomEditorConfigurer:用来注册自定义的属性编辑器
BeanFactoryPostProcessor类图: