Spring 之 InitializingBean
Spring 之 InitializingBean
1、简介
Spring中提供了 InitializingBean 接口,帮助用户实现一些自定义的初始化操作;在bean实例化、属性注入后的提供了一个扩展方法afterPropertiesSet();其实现方式很简单,需要bean实现InitializingBean 接口并且重写 afterPropertiesSet(),且bean要注册到Spring容器中,那么bean在实例化、属性注入后,重写的afterPropertiesSet()就会触发执行;与InitializingBean#afterPropertiesSet()类似效果的是init-method,但是需要注意的是InitializingBean#afterPropertiesSet()执行时机要略早于 init-method;initializingBean#afterPropertiesSet()的调用方式是在bean初始化过程中直接调用bean的afterPropertiesSet();而bean自定义属性init-method是通过java反射的方式进行调用 ;
InitializingBean#afterPropertiesSet() 与 init-method 的执行时机是在BeanPostProcessor#postProcessBeforeInitialization()和BeanPostProcessor#postProcessAfterInitialization()之间;
2、Bean 的生命周期
3、源码分析
1、AbstractApplicationContext#refresh是Spring容器启动的关键一步;
2、AbstractApplicationContext#finishBeanFactoryInitialization,是Spring容器启动最后一大步了,前面关于容器必需的组件基本上已经创建好了,这里主要是把需要Spring管理的单例bean实例化注册到Spring容器里;
3、DefaultListableBeanFactory#preInstantiateSingletons,从名字上看更可以看出来是要实例化单例类型的bean了;
4、AbstractBeanFactory#getBean(java.lang.String)-->AbstractBeanFactory#doGetBean
-->DefaultSingletonBeanRegistry#getSingleton(String,ObjectFactory),
要调用getSingleton(String,ObjectFactory)时,这里要注意一下ObjectFactory是一个函数式接口,使用了java8的lambda表达式的写法,在进入到getSingleton()方法内,执行到ObjectFactory#getObject()方法时,才会触发createBean()方法执行。
5、AbstractAutowireCapableBeanFactory#createBeanString,RootBeanDefinition, Object[])
-->AbstractAutowireCapableBeanFactory#doCreateBean,这时完成了Bean的实例化,属性还未注入;
6、AbstractAutowireCapableBeanFactory#createBeanString,RootBeanDefinition, Object[])
-->AbstractAutowireCapableBeanFactory#populateBean,完成属性的注入;
7、顺着AbstractAutowireCapableBeanFactory#populateBean往下执行到initializeBean(),BeanPostProcessor 的postProcessBeforeInitialization()和postProcessAfterInitialization()就是在这个方法中执行的;
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//执行BeanPostProcessor接口实现类的postProcessBeforeInitialization方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//如果bean实现了InitializingBean或者自定义了initMethod,
//会在这里执行InitializingBean#afterPropertiesSet和initMethod方法
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;
}
8、从最外层以剥洋葱的方式一层一层分析到这里,AbstractAutowireCapableBeanFactory#initializeBean()--->invokeInitMethods()才正式走入高潮部分,InitializingBean#afterPropertiesSet和initMethod方法的执行时机就在这里;
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
//判断bean是否实现了InitializingBean
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//如果实现了InitializingBean,真接调用afterPropertiesSet(),简单粗暴;
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
//尝试获取一下bean自定义的init-method方法
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
//如果自定义了init-method方法,在这里开始执行;
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
9、进入到invokeCustomInitMethod()内,使用java反射来执行自定义的init-method方法;
到这里InitializingBean#afterPropertiesSet方法和init-method是什么时候开始调用,是用什么方式来调用的呢,已经分析清楚了,同时还了解到InitializingBean#afterPropertiesSet方法和init-method有类似的效果,执行时机也比较接近,但是是两个完全不同的东西,且InitializingBean#afterPropertiesSet方法的执行时机要稍早于init-method。
4、应用场景
这个扩展点其实是比较有用的一个扩展点,可以用于修改默认设置的属性、添加补充额外的属性值,或者针对关键属性做校验。而Spring内部也有比较经典的实现,有些经常用到,但是可能没有觉察到,如Spring MVC中的RequestMappingHandlerMapping,完成了URL与controller的映射工作。