Spring - SmartInitializingSingleton扩展接口

简介: SmartInitializingSingleton扩展接口

@[toc]

在这里插入图片描述


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");

    }
}
    

在这里插入图片描述


相关文章
|
30天前
|
XML Java 数据格式
探索Spring之利剑:ApplicationContext接口
本文深入介绍了Spring框架中的核心接口ApplicationContext,解释了其作为应用容器的功能,包括事件发布、国际化支持等,并通过基于XML和注解的配置示例展示了如何使用ApplicationContext管理Bean实例。
62 6
|
3月前
|
存储 安全 Java
|
3月前
|
自然语言处理 JavaScript Java
Spring 实现 3 种异步流式接口,干掉接口超时烦恼
本文介绍了处理耗时接口的几种异步流式技术,包括 `ResponseBodyEmitter`、`SseEmitter` 和 `StreamingResponseBody`。这些工具可在执行耗时操作时不断向客户端响应处理结果,提升用户体验和系统性能。`ResponseBodyEmitter` 适用于动态生成内容场景,如文件上传进度;`SseEmitter` 用于实时消息推送,如状态更新;`StreamingResponseBody` 则适合大数据量传输,避免内存溢出。文中提供了具体示例和 GitHub 地址,帮助读者更好地理解和应用这些技术。
495 0
|
4月前
|
存储 数据采集 Java
Spring Boot 3 实现GZIP压缩优化:显著减少接口流量消耗!
在Web开发过程中,随着应用规模的扩大和用户量的增长,接口流量的消耗成为了一个不容忽视的问题。为了提升应用的性能和用户体验,减少带宽占用,数据压缩成为了一个重要的优化手段。在Spring Boot 3中,通过集成GZIP压缩技术,我们可以显著减少接口流量的消耗,从而优化应用的性能。本文将详细介绍如何在Spring Boot 3中实现GZIP压缩优化。
502 6
|
3月前
|
存储 NoSQL Java
Spring Boot项目中使用Redis实现接口幂等性的方案
通过上述方法,可以有效地在Spring Boot项目中利用Redis实现接口幂等性,既保证了接口操作的安全性,又提高了系统的可靠性。
75 0
|
5月前
|
JSON 安全 Java
|
5月前
|
存储 SQL Java
|
6月前
|
SQL Java 数据库
实时计算 Flink版产品使用问题之Spring Boot集成Flink可以通过什么方式实现通过接口启动和关闭Flink程序
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
5月前
|
JavaScript Java Spring
Spring Boot 接口返回文件流
Spring Boot 接口返回文件流
211 0