首先我们来看一下InitializingBean接口,发现它只有一个方法,所以实现该接口只需实现这个方法就可以了。
package org.springframework.beans.factory;
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
我们来定义一个service实现该接口,测试一下该接口提供的初始化功能,同时与init-method配置的初始化方法进行比较。
public class PlatformxService implements InitializingBean{
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化执行:afterPropertiesSet");
}
public void initMethod(){
System.out.println("初始化执行:initMethod");
}
}
在配置文件中进行该service配置
<bean id="platformxService" class="com.sfpay.platformx.service.PlatformxService" init-method="initMethod" />
因为我搭建的是web工程,这里启动容器观察初始化方法执行顺序
初始化执行:afterPropertiesSet
初始化执行:initMethod
这里我们可以看到在spring初始化bean的时候,afterPropertiesSet方法执行再前,initMethod方法执行在后,为什么会出现这种情况呢?我们就进一步看一下spring加载bean时候的源码。在AbstractAutowireCapableBeanFactory中我们可以找到spring调用bean初始化方法的代码。
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
throws Throwable {
//判断bean是否实现InitializingBean接口
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
//直接通过bean调用afterPropertiesSet方法
((InitializingBean) bean).afterPropertiesSet();
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
直接通过bean调用afterPropertiesSet方法
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null) {
//判断是否有配置init-method方法
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
//在该方法中调用init-method配置方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
我们再进入到invokeCustomInitMethod方法中查看,init-method配置初始化方法调用过程
protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
String initMethodName = mbd.getInitMethodName();
final Method initMethod = (mbd.isNonPublicAccessAllowed() ?
BeanUtils.findMethod(bean.getClass(), initMethodName) :
ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));
if (initMethod == null) {
if (mbd.isEnforceInitMethod()) {
throw new BeanDefinitionValidationException("Couldn't find an init method named '" +
initMethodName + "' on bean with name '" + beanName + "'");
}
else {
if (logger.isDebugEnabled()) {
logger.debug("No default init method named '" + initMethodName +
"' found on bean with name '" + beanName + "'");
}
// Ignore non-existent default lifecycle methods.
return;
}
}
if (logger.isDebugEnabled()) {
logger.debug("Invoking init method '" + initMethodName + "' on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
ReflectionUtils.makeAccessible(initMethod);
return null;
}
});
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
//通过反射调用初始化方法
initMethod.invoke(bean);
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
InvocationTargetException ex = (InvocationTargetException) pae.getException();
throw ex.getTargetException();
}
}
else {
try {
ReflectionUtils.makeAccessible(initMethod);
//通过反射调用初始化方法
initMethod.invoke(bean);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
由上代码我们知道为什么会出现上面执行顺序的结果了吧!同时我们还发现afterPropertiesSet方法不仅先执行,也是直接调用bean的afterPropertiesSet方法进行调用,而init-method初始方法是通过反射方式调用的。
通过上面实现及代码我们可以得出结果:1.spring为我们提供两种初始化bean方法,实现InitializingBean接口和配置init-method。2.实现InitializingBean接口的方式因为是直接对bean调用afterPropertiesSet方法所以比init-method配置反射方式调用效率上面会高一点,但是也增加了跟spring框架的耦合度。