Spring源码-IOC容器(五)-Bean的初始化

Spring IOC容器 源码解析系列,建议你们按顺序阅读,欢迎讨论spring

(spring源码均为4.1.6.RELEASE版本)编程

  1. Spring源码-IOC容器(一)-构建简单IOC容器
  2. Spring源码-IOC容器(二)-Bean的定位解析注册
  3. Spring源码-IOC容器(三)-GetBean
  4. Spring源码-IOC容器(四)-FactoryBean
  5. Spring源码-IOC容器(五)-Bean的初始化
  6. Spring源码-IOC容器(六)-bean的循环依赖
  7. Spring源码-IOC容器(七)-ApplicationContext
  8. Spring源码-IOC容器(八)-NamespaceHandler与自定义xml
  9. Spring源码-IOC容器(九)-Component-Scan源码解析
  10. Spring源码-IOC容器(十)-@Autowired解析

IOC容器(三)-GetBean中的AbstractBeanFactory的doCreateBean方法中,曾主要分析过三个方法app

  • createBeanInstance bean的实例化
  • populateBean bean属性和依赖的注入
  • initializeBean bean的初始化

这三个方法是按顺序执行的,显示实例化bean,再对bean的属性和依赖的注入,最后进行bean的初始化。bean的初始化就是bean对象被使用以前所要作的准备工做,在spring容器中主要作了下面几件事:post

  1. 若是bean实现了BeanNameAware、BeanClassLoaderAware或BeanFactoryAware接口,调用接口方法进行赋值
  2. 执行BeanPostProcessor接口中的postProcessBeforeInitialization方法
  3. 执行初始化方法,一个是bean实现了InitializingBean接口的afterPropertiesSet方法,另外一个是bean配置的init method
  4. 执行BeanPostProcessor接口中的postProcessAfterInitialization方法

上面的各个操做都是按顺序来进行的。为何单独花一章来讨论bean的初始化,由于涉及了几个经常使用的初始化方法,而它们的做用点从外部来看都是同样的,但实际的执行是有前后之分的。spa

1.init-method

init-method是在Spring的xml配置文件中经过bean标签的init-method属性来配置的。例如:.net

<bean id="sampleBean" class="com.lntea.spring.demo.bean.SampleBean" init-method="prepare"></bean>

即在bean的初始化时执行prepare方法代理

2.InitializingBean

InitializingBean是spring提供的编程方式的bean初始化接口code

public interface InitializingBean {

	void afterPropertiesSet() throws Exception;

}

实现afterPropertiesSet方法就会在spring初始化bean时执行xml

3.BeanPostProcessor

BeanPostProcessor是Spring重要的扩展方式之一,在bean的各个时期如实例化,配置,初始化等定义了回调方法进行扩展。这里只讨论默认的两个方法,用来在bean初始化的先后执行回调。对象

public interface BeanPostProcessor {

	// 初始化前回调方法
	Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

	// 初始化后回调方法
	Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}

再来强调下初始化过程当中执行的顺序:

BeanPostProcessor的初始化前置回调方法 -> InitializingBean接口的初始化方法 -> init-method初始化方法 -> BeanPostProcessor的初始化后置回调方法

从源码上再来看下

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {

	Object wrappedBean = bean;
	if (mbd == null || !mbd.isSynthetic()) {
		// 初始化前置回调方法
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}

	try {
		// 初始化方法
		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()) {
		// 初始化后置回调方法
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}
	return wrappedBean;
}

protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
		throws Throwable {

	boolean isInitializingBean = (bean instanceof InitializingBean);
	if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
		// 先执行InitializingBean的初始化
		((InitializingBean) bean).afterPropertiesSet();
	}

	if (mbd != null) {
		String initMethodName = mbd.getInitMethodName();
		if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
				!mbd.isExternallyManagedInitMethod(initMethodName)) {
			// 再执行init-method的初始化
			invokeCustomInitMethod(beanName, bean, mbd);
		}
	}
}

BeanPostProcessor自己只定义了两个回调方法,在初始化的先后执行,但继承它的子接口对bean实例化的各个节点都加入了扩展点,从而容许对bean的建立过程自定义各类操做。Spring的文档中这样提到:

If you want to implement some custom logic after the Spring container finishes instantiating, configuring, and initializing a bean, you can plug in one or more BeanPostProcessor implementations.

若是你Spring容器完成实例化,配置和初始化bean以后实现一些自定义的逻辑,能够插入一个或多个的BeanPostProcessor实现。

若是你深刻去读Spring源码时,会发现BeanPostProcessor的扩展点甚至能够直接替代原有的bean对象而返回一个代理对象,这也就给各类操做提供了可能性。具体之后再详细地分析吧。

相关文章
相关标签/搜索