Spring源码 - 核心接口SmartInitializingSingleton&InitializingBean

# 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()方法在BeanFactoryBean填充完属性之后进行激活。
  • afterPropertiesSet()方法允许Bean在最终初始化完成之后,针对BeanFactory的属性注入以及整体配置的验证。
  • afterPropertiesSet()方法可以在Bean发生错误配置(如未能设置一个基本属性)或者因为其他任何原因初始化失败而抛出异常。
  • InitializingBean接口有个功能类似的替换方案,即在XML配置文件中声明Bean时配置init-method初始化方法。

# 3、SmartInitializingSingleton&InitializingBean的区别

  • SmartInitializingSingleton接口只能作用于非惰性单实例BeanInitializingBean接口无此要求。
  • 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();
			}
		}
	}

上面的源码即为SpringSmartInitializingSingleton#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);
			}
		}
	}

上面的源码即为SpringInitializingBean的激活。其中一共做了两件事:

  • 1、Bean实例如果为InitializingBean类型实例则直接激活InitializingBean#afterPropertiesSet()
  • 2、如果Bean实例指定了init-method,则通过反射激活Bean指定的init-method
  • 3、如果SpringInitializingBean类型实例的激活异常,则不会调用Bean指定的init-method方法。
  • 4、Spring对于InitializingBean的激活是在Bean初始化完成之后。

GitHub源码地址https://github.com/kapbc/kapcb-spring-source/tree/master/Spring-Framework-v5.3.13

备注:此文为笔者学习Spring源码的笔记,鉴于本人技术有限,文中难免出现一些错误,感谢大家批评指正。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值