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

    }
}
    

在这里插入图片描述


相关文章
|
4天前
|
Java API 微服务
【Spring Boot系列】通过OpenAPI规范构建微服务服务接口
【4月更文挑战第5天】通过OpenAPI接口构建Spring Boot服务RestAPI接口
|
4天前
|
前端开发 安全 Java
Spring Boot 三招组合拳,手把手教你打出优雅的后端接口
Spring Boot 三招组合拳,手把手教你打出优雅的后端接口
45 0
|
4天前
|
Java Spring
spring boot访问接口报500
spring boot访问接口报500
13 2
|
4天前
|
Java 数据库连接 数据库
spring+mybatis_编写一个简单的增删改查接口
spring+mybatis_编写一个简单的增删改查接口
17 2
|
4天前
|
算法 NoSQL Java
限流艺术:Spring Boot接口限流的实用指南
限流艺术:Spring Boot接口限流的实用指南
104 0
限流艺术:Spring Boot接口限流的实用指南
|
4天前
|
负载均衡 网络协议 Java
构建高效可扩展的微服务架构:利用Spring Cloud实现服务发现与负载均衡
本文将探讨如何利用Spring Cloud技术实现微服务架构中的服务发现与负载均衡,通过注册中心来管理服务的注册与发现,并通过负载均衡策略实现请求的分发,从而构建高效可扩展的微服务系统。
|
4天前
|
数据采集 前端开发 NoSQL
Spring Boot反爬虫,防止接口盗刷
Spring Boot反爬虫,防止接口盗刷
26 1
|
4天前
ssm(Spring+Spring mvc+mybatis)Dao接口——IDeptDao
ssm(Spring+Spring mvc+mybatis)Dao接口——IDeptDao
9 0
|
4天前
|
Java Spring
使用JDBCTemplate实现与Spring结合,方法公用 ——接口(BaseDao)
使用JDBCTemplate实现与Spring结合,方法公用 ——接口(BaseDao)
9 0
|
4天前
|
存储 Java 数据处理
Spring揭秘:ClassPathScanningProvider接口应用场景及实现原理!
ClassPathScanningCandidateComponentProvider是Spring框架中一个非常核心的类,它主要用于在类路径下扫描并发现带有特定注解的组件,支持诸如@ComponentScan、@Component、@Service、@Repository和@Controller等注解的自动扫描和注册。
Spring揭秘:ClassPathScanningProvider接口应用场景及实现原理!