Spring - SmartInitializingSingleton扩展接口

Posted 小小工匠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring - SmartInitializingSingleton扩展接口相关的知识,希望对你有一定的参考价值。

文章目录


Pre

Spring Boot - 扩展接口一览


org.springframework.beans.factory.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();


触发时机

只有一个方法afterSingletonsInstantiated,其作用是是 在spring容器管理的所有单例对象(非懒加载对象)初始化完成之后调用的回调接口

其触发时机为postProcessAfterInitialization之后。


使用场景

可以扩展此接口在对所有单例对象初始化完毕后,做一些后置的业务处理


源码解析

org.springframework.context.support.AbstractApplicationContext#refresh
	org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
		org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
			smartSingleton.afterSingletonsInstantiated();

在Spring容器启动时,会调用方法refresh();

@Override
	public void refresh() throws BeansException, IllegalStateException 
		synchronized (this.startupShutdownMonitor) 
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// Prepare this context for refreshing.
			/**
			 * 做一些前期准备工作
			 * 1、为子类提供抽模板方法initPropertySources:子类可以把ServletContext中的参数对设置到Environment
			 * 2、校验环境变量属性
			 * 3、初始化earlyApplicationListeners
			 * 4、初始化earlyApplicationEvents
			 */
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			/**
			 * 为子类提供refreshBeanFactory()方法,子类可以对BeanFactory进行一些操作与设置
			 */
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			// Prepare the bean factory for use in this context.
			/**
			 * 准备BeanFactory
			 * 	1. 设置BeanFactory的类加载器BeanClassLoader、SpringEL表达式解析器beanExpressionResolver、类型转化注册器PropertyEditorRegistrar
			 * 	2. 添加三个BeanPostProcessor,注意是具体的BeanPostProcessor实例对象
			 *		2.1、ApplicationContextAwareProcessor:用来处理EnvironmentAware、EmbeddedValueResolverAware等回调setApplicationContext()方法
			 *		2.2、ApplicationListenerDetector:负责把实现了ApplicantsListener类型的Bean注册到ApplicationContext的监听列表
			 *		2.3、LoadTimeWeaverAwareProcessor:
			 *
			 * 	3. 记录ignoreDependencyInterface:如果一个属性对应的set方法在ignoredDependencyInterfaces接口中被定义了,则该属性不会被spring进行自动注入
			 * 		EnvironmentAware
			 * 		EmbeddedValueResolverAware
			 * 		ResourceLoaderAware
			 * 		ApplicationEventPublisherAware
			 * 		MessageSourceAware
			 * 		ApplicationContextAware
			 * 		ApplicationStartupAware
			 *
			 * 	4. 记录ResolvableDependency
			 * 		BeanFactory
			 * 		ResourceLoader
			 * 		ApplicationEventPublisher
			 * 		ApplicationContext
			 *
			 * 	5. 添加四个环境相关的单例Bean
			 * 			5.1、environment
			 * 			5.2、systemProperties
			 * 			5.3、systemEnvironment
			 * 			5.4、applicationStartup
			 */
			prepareBeanFactory(beanFactory);

			try 
				// Allows post-processing of the bean factory in context subclasses.
				/**
				 * 为子类提供的方法,子类可以对BeanFactory进行设置
				 * 此方法允许子类在所有的bean尚未初始化之前注册BeanPostProcessor。
				 *	通过XML和注解初始化无默认实现,
				 * 如果是WEB容器则此步会进行web容器scope(request、session、application)的注册和注册环境相关的bean等操作
				 */
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");

				// Invoke factory processors registered as beans in the context.
				/**
				 * 执行所有的BeanFactoryPostProcessor,包括自定义的和spring内置的,开始对BeanFactory进行处理
				 * 在此步骤内会将所有的bean对应的BeanDefinition解析出来放入到beanFactory的BeanDefinitionMap中
				 * 默认情况下,
				 * 		BeanFactory中的BeanDefinitionMap中有6个BeanDefinition,5个基础的+配置类AppConfig
				 * 		这6个中有一个BeanFactoryPostProcessor:ConfigurationClassPostProcessor,这个类主要是解析配置类,
				 * 			配置类:1、加了 @Configuration注解的Full配置类
				 * 				  2、加了 @Component,@ComponentScan,@Import,@ImportResource,@Bean 注解的 Lite配置类
				 * 		扫描的过程中可能又会扫描出其他的BeanFactoryPostProcessor,那么这些BeanFactoryPostProcessor也得在这一步执行
				 *
				 *
				 * BeanFactoryPostProcessors按入场方式分为:
				 * 1. 程序员调用ApplicationContext的API手动添加
				 * 2. Spring自己扫描出来的
				 *
				 * BeanFactoryPostProcessor按类型又可以分为:
				 * 1. 普通BeanFactoryPostProcessor
				 * 2. BeanDefinitionRegistryPostProcessor
				 *
				 * 执行顺序顺序如下:
				 * 1. 执行手动添加的BeanDefinitionRegistryPostProcessor                       	的postProcessBeanDefinitionRegistry()方法
				 * 2. 执行扫描出来的BeanDefinitionRegistryPostProcessor + 实现了PriorityOrdered 的postProcessBeanDefinitionRegistry()方法
				 * 3. 执行扫描出来的BeanDefinitionRegistryPostProcessor + 实现了Ordered		   	的postProcessBeanDefinitionRegistry()方法
				 * 4. 执行扫描出来的BeanDefinitionRegistryPostProcessor + 普通				   	的postProcessBeanDefinitionRegistry()方法
				 * 5. 执行扫描出来的BeanDefinitionRegistryPostProcessor + 所有				   	的postProcessBeanFactory()方法
				 * 6. 执行手动添加的BeanFactoryPostProcessor								   	的postProcessBeanFactory()方法
				 * 7. 执行扫描出来的BeanFactoryPostProcessor + 实现了PriorityOrdered 		   	的postProcessBeanFactory()方法
				 * 8. 执行扫描出来的BeanFactoryPostProcessor + 实现了Ordered 		   		   	的postProcessBeanFactory()方法
				 * 9. 执行扫描出来的BeanFactoryPostProcessor + 普通 				   		   	的postProcessBeanFactory()方法
				 *
				 * ConfigurationClassPostProcessor就会在第2步执行,会进行扫描
				 */
				invokeBeanFactoryPostProcessors(beanFactory);

				/**
				 * 扫描BeanPostProcessor实例化并排序,并添加到BeanFactory中的beanPostProcessor中
				 * 之前已经注册过三个
				 * 在这一步实例化BeanPostProcessor是因为BeanPostProcessor是用来干预bean的创建过程的,后面要实例化bean了,所以需要提前把所有的BeanPostProcessor实例化出来
				 *
				 * 扫描BeanPostProcessor顺序如下:
				 * 	1、注册: PostProcessorRegistrationDelegate.BeanPostProcessorChecker
				 * 	2、扫描并注册:实现PriorityOrdered接口的
				 * 	3、扫描并注册:实现Ordered接口的
				 * 	4、扫描并注册:未排序的
				 * 	5、扫描并注册:MergedBeanDefinitionPostProcessor的
				 * 	6、注册:ApplicationListenerDetector
				 */
				registerBeanPostProcessors(beanFactory);

				beanPostProcess.end();

				// Initialize message source for this context.
				// 设置ApplicationContext的MessageSource,要么是用户设置的,要么是DelegatingMessageSource
				initMessageSource();

				/**
				 * 初始化事件广播,作用是:发布事件,并且为所发布的事件找到对应的事件监听器。
				 * 设置ApplicationContext的applicationEventMulticaster,要么是用户设置的,要么是SimpleApplicationEventMulticaster
				 */
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 给子类的模板方法,执行其他的初始化操作,如和SpringMVC整合时,需要初始化一些其他的bean,默认是一个空方法
				onRefresh();

				// 把定义的ApplicationListener的Bean对象,设置到ApplicationContext中去,并执行在此之前所发布的事件
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				// 实例化其余的非懒加载的单例bean
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			

			catch (BeansException ex) 
				if (logger.isWarnEnabled()) 
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			

			finally 
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
				contextRefresh.end();
			
		
	

重点看 finishBeanFactoryInitialization

@Override
	public void refresh() throws BeansException, IllegalStateException 
		synchronized (this.startupShutdownMonitor) 
			 // .... 

			try 
			 		
				 // ....

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				 // ....
			

			catch (BeansException ex) 
			 // ....
			

			finally 
			 // ....
			
		
	

继续

	/**
	 * Finish the initialization of this context's bean factory,
	 * initializing all remaining singleton beans.
	 */
	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) 
		 // ...
		 
		// 实例化非懒加载的单例Bean
		// Instantiate all remaining (non-lazy-init) singletons.
		beanFactory.preInstantiateSingletons();
	

继续

	@Override
	public void preInstantiateSingletons() throws BeansException 
		 
		 // ....
		
		// 所有的非懒加载单例Bean都创建完了后
		// Trigger post-initialization callback for all applicable beans...
		for (String beanName : beanNames) 
			Object singletonInstance = getSingleton(beanName);
			// 如果实例实现了SmartInitializingSingleton,执行afterSingletonsInstantiated方法。 
			if (singletonInstance instanceof SmartInitializingSingleton) 
				// ....
				// 所有的非懒加载单例bean都创建完成之后调用
				 smartSingleton.afterSingletonsInstantiated();
				 
			
		
	


扩展示例

package com.artisan.bootspringextend.testextends;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.context.annotation.Configuration;

/**
 * @author 小工匠
 * @version 1.0
 * @description: TODO
 * @date 2022/12/6 23:23
 * @mark: show me the code , change the world
 */

@Slf4j
@Configuration
public class ExtendSmartInitializingSingleton implements SmartInitializingSingleton 
    @Override
    public void afterSingletonsInstantiated() 

        log.info("----->ExtendSmartInitializingSingleton#afterSingletonsInstantiated called");

    

    


以上是关于Spring - SmartInitializingSingleton扩展接口的主要内容,如果未能解决你的问题,请参考以下文章

Spring全家桶笔记:Spring+Spring Boot+Spring Cloud+Spring MVC

学习笔记——Spring简介;Spring搭建步骤;Spring的特性;Spring中getBean三种方式;Spring中的标签

Spring--Spring入门

Spring框架--Spring事务管理和Spring事务传播行为

Spring框架--Spring事务管理和Spring事务传播行为

Spring框架--Spring JDBC