简介

SmartInitializingSingleton是spring的扩展点之一,主要用于在Spring容器启动完成时进行扩展操作,其只有一个方法afterSingletonsInstantiated()。
触发的关键点是在单例预实例化阶段结束时调用,保证所有常规单例 bean 都已创建。接口的bean的作用域必须是单例才会触发。

spring容器中Bean的生命周期内所有可扩展的点的调用顺序
扩展接口 实现接口
ApplicationContextlnitializer initialize
AbstractApplicationContext refreshe
BeanDefinitionRegistryPostProcessor postProcessBeanDefinitionRegistry
BeanDefinitionRegistryPostProcessor postProcessBeanFactory
BeanFactoryPostProcessor postProcessBeanFactory
instantiationAwareBeanPostProcessor postProcessBeforelnstantiation
SmartlnstantiationAwareBeanPostProcessor determineCandidateConstructors
MergedBeanDefinitionPostProcessor postProcessMergedBeanDefinition
InstantiationAwareBeanPostProcessor postProcessAfterlnstantiation
SmartInstantiationAwareBeanPostProcessor getEarlyBeanReference
BeanFactoryAware postProcessPropertyValues
ApplicationContextAwareProcessor invokeAwarelnterfaces
BeanNameAware setBeanName
InstantiationAwareBeanPostProcessor postProcessBeforelnstantiation|
BeanNameAware setBeanName
@PostConstruct
InitializingBean afterPropertiesSet
FactoryBean getobject
SmartlnitializingSingleton afterSingletonslnstantiated
CommandLineRunner run
DisposableBeandestroy

源码分析

方法 preInstantiateSingletons实例化非懒加载的单例Bean

@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.
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				if (isFactoryBean(beanName)) {
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean 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());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					getBean(beanName);
				}
			}
		}

		// Trigger post-initialization callback for all applicable beans...
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			// 如果实例实现了SmartInitializingSingleton,执行afterSingletonsInstantiated方法。
			if (singletonInstance instanceof SmartInitializingSingleton) {
				StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
						.tag("beanName", beanName);
				SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					// 所有的非懒加载单例bean都创建完成之后调用
					smartSingleton.afterSingletonsInstantiated();
				}
				smartInitialize.end();
			}
		}
	}

应用场景

SmartInitializingSingleton 提供了一种在所有单例 Bean 实例化后但在应用完全启动之前执行自定义逻辑的机制。它主要用于那些需要在所有 Bean 完全实例化后进行全局初始化、处理依赖关系、配置外部库或确保初始化顺序的场景。

示例代码

@Slf4j
@Configuration
public class ExtendSmartInitializingSingleton implements SmartInitializingSingleton {

    private ListableBeanFactory beanFactory;

    public ExtendSmartInitializingSingleton(ListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    @Override
    public void afterSingletonsInstantiated() {
        String[] beanNames = beanFactory.getBeanNamesForType(TestAutowired.class);
        for (String s : beanNames) {
            log.info("=================================");
            log.info(s);
        }
    }
}

运行示例

在这里插入图片描述

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部