使用背景
因为需要支持其他项目组改造任务,需要了解该系统相关框架和部分代码,在查看该系统已开发好的模块时,发现对于配置类,使用了不同的bean初始化方式。
如下:
分别使用了spring中的InitializingBean和@Bean的初始化,由于InitializingBean之前没有使用过,所以来学习一下。
附spring中bean实例化过程如下:
说明
InitializingBean接口只包含一个方法afterPropertiesSet(),凡是继承了InitializingBean接口的类,在初始化时都会调用这方法。
源码及分析:(网络参考)
package org.springframework.beans.factory;
/**
* //由bean实现的接口,一旦bean工厂设置了它们的所有属性,就需要对其进行响应:
* 例如,执行定制初始化,或检查所有强制属性是否已设置。
* Interface to be implemented by beans that need to react once all their
* properties have been set by a BeanFactory: for example, to perform custom
* initialization, or merely to check that all mandatory properties have been set.
*
* //实现InitializingBean的另一种方法是指定一个定制的init-方法,例如在XML bean定义中
* <p>An alternative to implementing InitializingBean is specifying a custom
* init-method, for example in an XML bean definition.
* For a list of all bean lifecycle methods, see the
* {@link BeanFactory BeanFactory javadocs}.
*
* @author Rod Johnson
* @see BeanNameAware
* @see BeanFactoryAware
* @see BeanFactory
* @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
* @see org.springframework.context.ApplicationContextAware
*/
public interface InitializingBean {
/**
*//在BeanFactory设置了提供的所有bean属性后调用,
*//此方法允许bean实例仅在设置了所有bean属性之后才能执行初始化,并在配置错误时抛出异常。
*//在发生错误配置(如设置基本属性失败)或初始化失败的情况下会抛出Exception
* Invoked by a BeanFactory after it has set all bean properties supplied
* (and satisfied BeanFactoryAware and ApplicationContextAware).
* <p>This method allows the bean instance to perform initialization only
* possible when all bean properties have been set and to throw an
* exception in the event of misconfiguration.
* @throws Exception in the event of misconfiguration (such
* as failure to set an essential property) or if initialization fails.
*/
void afterPropertiesSet() throws Exception;
}
通过上述的注释以及方法名可了解到,InitializingBean中的afterPropertiesSet()方法是在属性设置后调用的。
在bean容器启动后才可以对bean进行实例化,Bean容器的最终实现类AbstractAutowireCapableBeanFactory中,包含了如下内容:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//...省略很多代码 下面开始初始化 关键就是两个步骤
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper); //这里执行了注入属性和依赖的操作
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);//这里执行了initMethod 和 afterPropertiesSet
}
}
//...省略很多代码
return exposedObject;
}
主要看到了initializeBean(beanName, exposedObject, mbd);这里执行了initMethod 和 afterPropertiesSet,继续追踪源码,
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
//这里判断是BeanFactoryAware, ServletContextAware之类的aware类型,如果是的话就执行对于的Aware方法
//把beanFactory啊 servletContext啊之类的依赖set进去
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//如果实现了BeanPostProcessor接口 这里会执行postProcessBeforeInitialization方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//这里就开始执行initMethod 和 afterPropertiesSet方法
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);//先判断是否实现了InitializingBean接口
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
//.....省略很多代码
else {
//执行afterPropertiesSet()方法
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null) {
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
//如果配置了initMethod 就执行initMethod方法 这里只是取到了方法名,显然是要通过反射调用了
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
至此可以看到执行了afterPropertiesSet()方法。
小结
通过上述可以了解:
1.Spring为bean提供了两种初始化bean的方式,分别是实现InitializingBean接口,或者是使用init-method,两种方式可以同时使用。
2.实现InitializingBean接口是直接调用的afterPropertiesSet()方法,init-method是通过反射实现,相比较下,实现接口效率较高,但是对spring有依赖。
3.如果调用afterPropertiesSet()方法时出错,则不调用init-method指定的方法。