spring4 IOC的init-method源码
init-method的例子
public class User {
public User() {
System.out.println("User实例已经创建!");
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void initUser() {
System.out.println("Bean初始化执行的方法");
}
}
<beans:bean id="user" class="cn.spy.spring.source.code.User" init-method="initUser">
<beans:property name="name" value="zhangsan"></beans:property>
</beans:bean>
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
}
结果:
为什么没有获取bean,就已经加载bean了?
由于在spring ioc初始化阶段,实例化非懒加载方式的一些单例。而这些bean被实例化之后,其init-method字段配置的方法名称作为bean的属性(注意:记住的是方法名称),被检查到如果存在,则回调该方法,回调方式只是通过方法名称进行反射而已。
读取bean配置的init-method标签
读取init-method标签是伴随着读取bean标签是一样的,只是作为bean标签的子节点而已。使用Dom技术读取XML文档(ResouceLoader读取),得到Resouce对象,将Resouce对象转化为Document对象。获取Document中的Element元素对象都封装为BeanDefinition,将BeanDefinition添加到BeanDefinitionMap集合映射中,最终添加到Spring IOC的管理容器BeanFactory(具体是DefaultListBeanFactory)。
处理给定的Bean标签的方法processBeanDefinition
执行init-method配置的方法
执行init-method配置的方法已经在beanFactory的BeanDefinitionMap中。
执行init-method配置的方法的流程:
4.png
从refresh方法开始,finishBeanFactoryInitialization方法; 预先加载bean,从BeanDefinitionMap中加载bean名称集合,遍历集合,调用getBean方法先生成bean,最后委派到doCreateBean方法:createBeanInstance创建bean实例,populateBean方法为实例属性填充,之后初始化方法initializeBean:检查bean是否注册了init-method,如果注册了,那么执行回调,调用init-method注册的方法,只是采用反射的方式来执行该方法。
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 + "'");
}
// 传入的bean如果实现了InitializingBean接口
// 那么可以执行afterPropertiesSet方法
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
((InitializingBean) bean).afterPropertiesSet();
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null) {
// 获取init-method指定方法的名称
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// 反射方式执行该方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
// 使用jdk反射方式调用bean指定的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>() {
@Override
public Object run() throws Exception {
ReflectionUtils.makeAccessible(initMethod);
return null;
}
});
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
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();
}
}
}