本文参考了
https://javadoop.com/post/spring-ioc
该文是基于Spring 4.3.9.release版本展开的
对于Java开发者来说,Spring绝对不会陌生,那么其中Spring容器的初始化过程是怎样的呢?该文简要跟踪了ClassPathXmlApplicationContext初始化的过程,现与大家分享。
首先给个ClassPathXmlApplicationContext使用的小例子,直观感受一下。
定义如下测试Bean:
public class TestBean implements InitializingBean, DisposableBean, BeanNameAware, BeanFactoryAware{
/**
* @Value和@Autoware是由AutowiredAnnotationBeanPostProcessor处理的;
* 如果程序中不引入AutowiredAnnotationBeanPostProcessor,则无法解析
* */
//在properties文件中配置了username=test
@Value("${username}")
private String userName;
private Integer age;
public void setUserName(String userName){
System.out.println("set 方法被调用.....");
this.userName = userName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getUserName(){
return this.userName;
}
public TestBean(){
System.out.println("Constructor : 构造器被调用..... | username: "+userName+" | age: "+age);
}
public void init(){
System.out.println("XML : xml文件中init-method指定的方法init被调用..... | username: "+userName+" | age: "+age);
}
public void destroyInXml(){
System.out.println("XML : xml文件中destory-method指定的方法destory被调用..... | username: "+userName+" | age: "+age);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("Aware : BeanFactoryAware.setBeanFactory被调用..... | username: "+userName+" | age: "+age);
}
@Override
public void setBeanName(String name) {
System.out.println("Aware : BeanNameAware.setBeanName被调用..... | username: "+userName+" | age: "+age);
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean : destroy()被调用..... | username: "+userName+" | age: "+age);
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean : afterPropertiesSet()被调用..... | username: "+userName+" | age: "+age);
}
/**
* 默认情况下,Spring不认识@PostConstruct和@PreDestroy注解。
* 要启用这两个注解,要么注册CommonAnnotationBeanPostProcessor,要么添加配置<context:annotation-config />
* */
@PostConstruct
public void postConstruct(){
System.out.println("@PostConstruct : 被调用..... | username: "+userName+" | age: "+age);
}
@PreDestroy
public void preDestroy(){
System.out.println("@PreDestroy : 被调用..... | username: "+userName+" | age: "+age);
}
public String toString(){
System.out.println(this);
System.out.println("toString()..... | userName : "+userName+" | age: "+age);
return "";
}
}
bean的配置如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
default-lazy-init="false">
<!--context标签由ContextNamespaceHandler处理,同理,别的标签由相应的XXXNamespaceHandler处理-->
<context:property-placeholder location="classpath*:config/*.properties"/>
<context:annotation-config />
<bean id="myBeanPostProcessor" class="init.MyBeanPostProcessor" />
<bean id="myInstantiationPostProcessor" class="init.MyInstantiationPostProcessor" />
<bean id="myBeanFactoryPostProcessor" class="init.MyBeanFactoryPostProcessor" />
<bean id="testBean" class="init.TestBean" init-method="init" destroy-method="destroyInXml" >
<property name="age" value="20"/>
</bean>
</beans>
自定义的三个后处理器
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition testBean = beanFactory.getBeanDefinition("testBean");
System.out.println("BeanFactoryPostProcessor : postProcessBeanFactory被调用.....");
}
}
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof TestBean)
System.out.println("BeanPostProcessor : postProcessBeforeInitialization被调用.....| username : "+((TestBean) bean).getUserName()+" | age: "+((TestBean) bean).getAge());
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof TestBean)
System.out.println("BeanPostProcessor : postProcessAfterInitialization被调用..... | username : "+((TestBean) bean).getUserName()+" | age: "+((TestBean) bean).getAge());
return bean;
}
}
public class MyInstantiationPostProcessor extends AutowiredAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanName.equals("testBean"))
System.out.println("InstantiationAwareBeanPostProcessor : postProcessBeforeInstantiation.....");
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (beanName.equals("testBean"))
System.out.println("InstantiationAwareBeanPostProcessor : postProcessAfterInstantiation.....| username : "+((TestBean) bean).getUserName() +" | age: "+((TestBean) bean).getAge());
return true;
}
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
throws BeansException {
if (bean instanceof TestBean)
System.out.println("InstantiationAwareBeanPostProcessor : postProcessPropertyValues.....| username : "+((TestBean) bean).getUserName() +" | age: "+((TestBean) bean).getAge());
return pvs;
}
}
启动Spring容器:
public class Main {
public static void main(String[] args){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath*:bean.xml");
TestBean testBean = (TestBean) context.getBean("testBean");
//context.getBeanFactory().destroySingletons();
}
}
运行结果如下:
BeanFactoryPostProcessor : postProcessBeanFactory被调用.....
InstantiationAwareBeanPostProcessor : postProcessBeforeInstantiation.....
Constructor : 构造器被调用..... | username: null | age: null
InstantiationAwareBeanPostProcessor : postProcessAfterInstantiation.....| username : null | age: null
InstantiationAwareBeanPostProcessor : postProcessPropertyValues.....| username : test | age: null
Aware : BeanNameAware.setBeanName被调用..... | username: test | age: 20
Aware : BeanFactoryAware.setBeanFactory被调用..... | username: test | age: 20
BeanPostProcessor : postProcessBeforeInitialization被调用.....| username : test | age: 20
@PostConstruct : 被调用..... | username: test | age: 20
InitializingBean : afterPropertiesSet()被调用..... | username: test | age: 20
XML : xml文件中init-method指定的方法init被调用..... | username: test | age: 20
BeanPostProcessor : postProcessAfterInitialization被调用..... | username : test | age: 20
Bean的初始化过程会调用很多PostProcessor,那么顺序是怎样的呢?我们从ClassPathXmlApplicationContext的启动过程分析一下。
从上图可看出,ClassPathXmlApplicationContext的启动过程中,有两个步骤是比较重要的,obtainFreshBeanFactory()和finishBeanFactoryInitialization();前一个方法负责读取xml文件,并将这些信息转化为BeanDefinition保存在BeanFactory的map中,后一个方法负责创建(Instantiation)并初始化(Initialization)bean。
在此,简要分析一下后一个方法的主要部分。该方法最后会进入到AbstractAutowireCapableBeanFactory的doCreateBean()中。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// 省略不重要的代码
if (instanceWrapper == null) {
//运用反射创建bean,此时bean中的属性都没有赋值
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
......
try {
//调用一些PostProcessor方法
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
//属性赋值
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
......
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
......
return exposedObject;
}
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
......
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
//子类覆写该方法时,不要返回false,否则代码就会跳出
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
......
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//这里会使用AutowiredAnnotationBeanPostProcessor对@Autowire和@Value修饰的属性赋值
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
//最后对一般的属性赋值,赋值时又涉及到字段类型的转换问题,后续再分析
applyPropertyValues(beanName, mbd, bw, pvs);
}
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
//调用Aware类的方法,比如BeanNameAware
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
//调用Aware类的方法,比如BeanNameAware
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//调用BeanPostProcessor的postProcessBeforeInitialization()
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//调用afterPropertiesSet()和init-method方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//调用BeanPostProcessor的postProcessAfterInitialization()
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
从上述代码的分析过程,就可以看出前面例子的结果的顺序为何是这样。
补充几点说明:
- BeanPostProcessor的postProcessBeforeInitialization()的调用时机是在bean的所有属性赋值之后,而不是之前。这里的before Initialization强调的是init-method这些方法之前;
- @Value和@Autowire修饰的属性的赋值要在普通属性之前;
- Spring中的注释都是由BeanPostProcessor处理的,比如@Autowire由AutowiredAnnotationBeanPostProcessor处理,@Required由RequiredAnnotationBeanPostProcessor处理,Java自带的@PostConstruct等由CommonAnnotationBeanPostProcessor处理,这些Processor可以由<context:annotation-config />一键引入,<context:xxx />又由ContextNamespaceHandler解析。