# Spring
源码 - 核心接口SmartInitializingSingleton
&InitializingBean
Spring
版本:Spring 5.3.13-release
# 1、核心接口SmartInitializingSingleton
SmartInitializingSingleton
接口:
public interface SmartInitializingSingleton {
/**
* Invoked right at the end of the singleton pre-instantiation phase,
* with a guarantee that all regular singleton beans have been created
* already. {@link ListableBeanFactory#getBeansOfType} calls within
* this method won't trigger accidental side effects during bootstrap.
* <p><b>NOTE:</b> This callback won't be triggered for singleton beans
* lazily initialized on demand after {@link BeanFactory} bootstrap,
* and not for any other bean scope either. Carefully use it for beans
* with the intended bootstrap semantics only.
*/
void afterSingletonsInstantiated();
}
SmartInitializingSingleton
接口中的afterSingletonsInstantiated()
方法将会在所有的非惰性单实例Bean
初始化完成之后进行回调。可以避免早期初始化的意外副作用。SmartInitializingSingleton
可以看作是在所有的Bean
初始化完成结束后的InitializingBean
接口的替代。从注释文档中可以得到几点SmartInitializingSingleton
接口的相关信息:
SmartInitializingSingleton
接口只对非惰性单实例Bean
触发。afterSingletonsInstantiated()
方法是在所有非惰性单实例Bean
初始化完成之后进行回调。SmartInitializingSingleton
接口可以作为InitializingBean
接口的一种替代方案。
# 2、核心接口InitializingBean
InitializingBean
接口:
public interface InitializingBean {
/**
* Invoked by the containing {@code BeanFactory} after it has set all bean properties
* and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
* <p>This method allows the bean instance to perform validation of its overall
* configuration and final initialization when all bean properties have been set.
* @throws Exception in the event of misconfiguration (such as failure to set an
* essential property) or if initialization fails for any other reason
*/
void afterPropertiesSet() throws Exception;
}
InitializingBean
接口的作用,Spring
给出的官方解释是:实现InitializingBean
接口的Bean
,该Bean
实例化后Bean
中所有的属性被BeanFactory
进行注入之后的,检查所有强制性属性的设置。从注释文档中可以得到几点InitializingBean
接口的相关信息:
afterPropertiesSet()
方法在BeanFactory
为Bean
填充完属性之后进行激活。afterPropertiesSet()
方法允许Bean
在最终初始化完成之后,针对BeanFactory
的属性注入以及整体配置的验证。afterPropertiesSet()
方法可以在Bean
发生错误配置(如未能设置一个基本属性)或者因为其他任何原因初始化失败而抛出异常。InitializingBean
接口有个功能类似的替换方案,即在XML
配置文件中声明Bean
时配置init-method
初始化方法。
# 3、SmartInitializingSingleton
&InitializingBean
的区别
SmartInitializingSingleton
接口只能作用于非惰性单实例Bean
,InitializingBean
接口无此要求。SmartInitializingSingleton
接口是在所有非惰性单实例初始化完成之后进行激活回调,InitializingBean
接口是在每一个Bean
实例初始化完成之后进行激活回调。
# 4、SmartInitializingSingleton
&InitializingBean
的激活时机
# 4.1、SmartInitializingSingleton
的激活
SmartInitializingSingleton
的激活是在Spring
容器刷新中的finishBeanFactoryInitialization()
方法中完成的。具体代码在DefaultListableBeanFactory#preInstantiateSingletons()
方法中进行激活。
DefaultListableBeanFactory#preInstantiateSingletons()
激活代码,省略了:
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
// 创建 beanDefinitionNames 的副本 beanNames 用于后续的遍历, 以允许使用 init 等方法注册新的 BeanDefinition
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
// 触发所有非延迟加载单例 Bean 的初始化, 遍历 BeanName 集合对象
for (String beanName : beanNames) {
// Bean 定义信息的公共抽象类是 AbstractBeanDefinition, 普通的 Bean 在 Spring 解析 Bean 定义信息时实例化出来的是 GenericBeanDefinition
// Spring 上下文包括实例化所有 Bean 使用的 AbstractBeanDefinition 是 RootBeanDefinition
// 使用 getMergedLocalBeanDefinition 方法做了一次转化, 将非 RootBeanDefinition 转换为 RootBeanDefinition 以供后续操作
// 注意, 如果当前 BeanDefinition 存在父 BeanDefinition, 会基于父 BeanDefinition 生成一个 RootBeanDefinition, 然后在将调用 OverrideFrom 子 BeanDefinition 的相关属性覆写进去
// 合并父类 BeanDefinition
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 条件判断。非抽象类 && 单例 && 非懒加载, 则开始创建单例对象, 通过调用 getBean(beanName) 方法进行初始化
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 判断是否实现 BeanFactory 接口, 如果实现了 BeanFactory 接口, 判断是否立即初始化
// 判断 Bean 是否立即初始化, 根据 Bean 是否实现了 SmartFactoryBean 接口并重写内部方法 isEagerInit 并返回 true
if (isFactoryBean(beanName)) {
// 如果是 FactoryBean 则根据 & + BeanName 来获取 IOC 容器中的 FactoryBean 对象
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
// 如果根据 '&' + BeanName 获取的 Bean 是 FactoryBean 类型实例
if (bean instanceof FactoryBean) {
// 将 Bean 强制类型转换为 FactoryBean<?>
FactoryBean<?> factory = (FactoryBean<?>) bean;
// 判断这个 FactoryBean 是否希望立即初始化
boolean isEagerInit;
// 判断 Bean 是否实现了 SmartFactoryBean 接口, 如果实现了 SmartFactoryBean 则调用 isEagerInit
// 方法判断是否希望急切的进行初始化
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
// 如果希望急切的进行初始化则调用 getBean 方法通过 beanName 获取 Bean 实例对象
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 如果 beanName 对应的 Bean 不是 FactoryBean, 只是普通 Bean, 调用 getBean 方法通过 beanName 获取 Bean 实例对象
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
// 遍历 beanNames, 触发所有 SmartInitializingSingleton 后初始化的回调
for (String beanName : beanNames) {
// 获取 beanName 对应的单例Bean实例对象
Object singletonInstance = getSingleton(beanName);
// 判断获取的 singletonInstance 单例Bean对象是否实现了 SmartInitializingSingleton 接口
if (singletonInstance instanceof SmartInitializingSingleton) {
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
// 将获取的 singletonInstance 类型转换为 SmartInitializingSingleton 接口
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
// 触发 SmartInitializingSingleton 实现类的 afterSingletonsInstantiated() 方法
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
smartInitialize.end();
}
}
}
上面的源码即为Spring
对SmartInitializingSingleton#afterSingletonsInstantiated()
的激活。其中一共做了两件事:
- 1、使用
getBean()
方法对Bean
初始化例化。 - 2、对
SmartInitializingSingleton#afterSingletonsInstantiated()
进行激活。 - 3、
Spring
对于SmartInitializingSingelton
的激活是在所有非惰性单实例Bean
初始化完成之后。
# 4.1、InitializingBean
的激活
InitializingBean
接口的激活是在Spring
进行getBean()
的时候完成的。具体代码在AbstractAutowireCapableBeanFactory#invokeInitMethods()
方法中进行激活:
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 + "'");
}
// 如果 Bean 是 InitializingBean 实例类型则直接调用 InitializingBean 的 afterPropertiesSet 方法
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
// 激活 afterPropertiesSet 方法
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 激活 afterPropertiesSet 方法
((InitializingBean) bean).afterPropertiesSet();
}
}
// MergedBeanDefinition 不为空 && Bean 是不 NullBean
if (mbd != null && bean.getClass() != NullBean.class) {
// 获取自定义的 init-method 方法名称
String initMethodName = mbd.getInitMethodName();
// 判断是否指定了 init-method 方法, 如果指定了 init-method 方法, 则再调用制定的 init-method
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// 通过反射调用 init-method
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
上面的源码即为Spring
对InitializingBean
的激活。其中一共做了两件事:
- 1、
Bean
实例如果为InitializingBean
类型实例则直接激活InitializingBean#afterPropertiesSet()
。 - 2、如果
Bean
实例指定了init-method
,则通过反射激活Bean
指定的init-method
。 - 3、如果
Spring
对InitializingBean
类型实例的激活异常,则不会调用Bean
指定的init-method
方法。 - 4、
Spring
对于InitializingBean
的激活是在Bean
初始化完成之后。
GitHub源码地址:https://github.com/kapbc/kapcb-spring-source/tree/master/Spring-Framework-v5.3.13
备注:此文为笔者学习
Spring
源码的笔记,鉴于本人技术有限,文中难免出现一些错误,感谢大家批评指正。