2989 2024-01-17 2024-11-17

Spring总结篇,不同于之前抽丝剥茧式地纵向深入源码,本次从横向的角度出发,希望可以带个读者一个完全不同的Spring视角。

2024年重置版,搞点不一样的东西。希望通过本篇的内容,将之前的文章全部给串起来。

相关前文:

一、Bean的生命周期

我们先从狭义上进行简单划分:

  1. 实例化前(Before Instantiation):执行 cls.newInstance 之前,AOP动态代理、池化操作在此步进行。
  2. 实例化(Instantiation):执行 cls.newInstance 。
  3. 实例化后(After Instantiation):执行 cls.newInstance 之后。
  4. 填充属性(Population of Properties):注入字段,处理@Autowired、@Value、@Resource。
  5. 初始化前(Before Initialization):给与Aware接口资源
  6. 初始化(Initialization):执行@PostConstruct、执行afterPropertiesSet方法、init-method,执行顺序依次降低。
  7. 初始化后(After Initialization):无特殊操作。
  8. 使用中(In Use):代码运行中...
  9. 销毁(Destruction):分销毁前、销毁后。

如下是一张图,较为全貌地展示了bean的生命周期

bean的生命周期

二、BeanPostProcessor

我们再看下一个Bean在整个生命周期中都会经过哪些Spring内置的BeanPostProcessor,我们在其中的各个环节都可以做些什么。

便于理解,这里只列举关键BeanPostProcessor接口,不会过多扩展。

1、测试代码

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;

import javax.annotation.PostConstruct;
import java.lang.reflect.Constructor;

public class BeanPostProcessorTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanPostProcessorTest.class);
        context.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
        Object testBean = context.getBean("testBean");
        System.out.println(testBean);
    }

    // Spring框架内部专用接口
    @Bean
    public SmartInstantiationAwareBeanPostProcessorCls smartInstantiationAwareBeanPostProcessorCls() {
        return new SmartInstantiationAwareBeanPostProcessorCls();
    }
    // bean实例化前后调用,BeanPostProcessor接口的扩展
    // 主要用途为AOP动态代理(实例化之前)、@Autowird/@Resource字段注入(实例化之后/填充属性)
    @Bean
    public InstantiationAwareBeanPostProcessorCls instantiationAwareBeanPostProcessorCls() {
        return new InstantiationAwareBeanPostProcessorCls();
    }
    // bean初始化前后调用
    // afterPropertiesSet 归属于初始化中
    @Bean
    public BeanPostProcessorCls beanPostProcessorCls() {
        return new BeanPostProcessorCls();
    }
    private static class TestBean implements InitializingBean, DisposableBean {
        @Autowired
        private Animal animal;

        @PostConstruct
        public void init() {
            System.out.println("- 8.1 PostConstruct:已经激活Aware接口且bean所有属性已设置完毕");
        }

        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("- 8.2 InitializingBean.afterPropertiesSet:get a animal:" + animal.name);
        }

        @Override
        public void destroy() throws Exception {
            System.out.println("F2:DisposableBean.destroy:销毁bean");
        }

        @Override
        public String toString() {
            return "animal name is " + (animal == null ? null : animal.name);
        }
    }

    @Bean
    public Animal panda() {
        return new Animal("国宝熊猫");
    }

    private static class Animal {
        String name = "no name";
        public Animal(String name) {
            System.out.println("- 3. Animal init:" + name);
            this.name = name;
        }
        @Override
        public String toString() {
            return "animal name is " + name;
        }
    }

    // InstantiationAwareBeanPostProcessor接口的扩展,添加了一个回调,用于预测已处理 bean 的最终类型。该接口为特殊用途接口,主要供框架内部使用
    // 通常,应用程序提供的后处理器应该简单地实现普通 BeanPostProcessor 接口或从类派生 InstantiationAwareBeanPostProcessorAdapter
    private static class SmartInstantiationAwareBeanPostProcessorCls implements SmartInstantiationAwareBeanPostProcessor {
        @Override
        public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
            // 这个接口主要是spring框架内部来使用
            // 用来返回目标对象的类型(比如代理对象通过raw class获取proxy type 用于类型匹配)
            System.out.println("- 1. SmartInstantiationAwareBeanPostProcessor.predictBeanType:预测Bean类型: " + beanName + ", " + beanClass);
            return null;
        }

        @Override
        public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
            // 这里提供一个拓展点用来解析获取用来实例化的构造器(比如未通过bean定义构造器以及参数的情况下,会根据这个回调来确定构造器)
            System.out.println("- 3. SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors:确定候选构造器: "+ beanName + ", " + beanClass);
            return null;
        }

        @Override
        public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
            // 获取要提前暴露的bean的引用,用来支持单例对象的循环引用(一般是bean自身,如果是代理对象则需要取用代理引用)
            System.out.println("C3");
            return null;
        }
    }

    // 通常用于抑制特定目标 bean 的默认实例化,例如创建具有特殊TargetSources的代理(池化目标、延迟初始化目标、AOP动态代理等),或实现其他注入策略,例如字段注入
    private static class InstantiationAwareBeanPostProcessorCls implements InstantiationAwareBeanPostProcessor {
        // 实例化前后的后处理
        @Override
        public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
            // 这个方法用来在对象实例化前直接返回一个对象(如代理对象)来代替通过内置的实例化流程创建对象;
            System.out.println("- 2. InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation:实例化之前: " + beanName + ", " + beanClass);
            return null;
        }

        @Override
        public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
            // 在对象实例化完毕,执行populateBean之前,如果返回false则spring不再对对应的bean实例进行自动依赖注入。
            System.out.println("- 5. InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation:实例化完成之后: " + beanName + ", " + bean);
            return true;
        }

        @Override
        public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
            // 这里是在spring处理完默认的成员属性,应用到指定的bean之前进行回调,可以用来检查和修改属性,最终返回的PropertyValues会应用到bean中
            // @Autowired、@Resource等就是根据这个回调来实现最终注入依赖的属性的。
            System.out.println("- 6. InstantiationAwareBeanPostProcessor.postProcessProperties:开始注入/填充属性: " + beanName + ", " + bean + ", " + pvs);
            return pvs;
        }
    }

    private static class BeanPostProcessorCls implements BeanPostProcessor {
        // 初始化前后的后处理
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            // 该方法在bean实例化完毕(且已经注入完毕),在afterPropertiesSet或自定义init方法执行之前
            System.out.println("- 7. BeanPostProcessor.postProcessBeforeInitialization:BeanPostProcessor:实例化完成,初始化开始: " + beanName + ", " + bean);
            return bean;
        }

        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            // 在afterPropertiesSet或自定义init方法执行之后
            System.out.println("- 9. BeanPostProcessor.postProcessAfterInitialization:初始化结束");
            return bean;
        }
    }
}

2、Spring初始化日志

22:25:55.634 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@4fccd51b
22:25:55.662 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
22:25:55.784 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
22:25:55.788 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
22:25:55.790 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
22:25:55.793 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
22:25:55.800 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'beanPostProcessorCls'
22:25:55.802 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'beanLifeCycleTest'
22:25:55.810 [main] INFO org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'beanLifeCycleTest' of type [site.xiaokui.db.spring.BeanLifeCycleTest] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
22:25:55.813 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'instantiationAwareBeanPostProcessorCls'
22:25:55.814 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'smartInstantiationAwareBeanPostProcessorCls'
22:25:55.816 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'mergedBeanDefinitionPostProcessorCls'
22:25:55.816 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'destructionAwareBeanPostProcessorCls'

3、自定义输出

# 初始化 Animal
- 1. SmartInstantiationAwareBeanPostProcessor.predictBeanType:预测Bean类型: panda, class site.xiaokui.db.spring.BeanPostProcessorTest$Animal
- 1. SmartInstantiationAwareBeanPostProcessor.predictBeanType:预测Bean类型: panda, class site.xiaokui.db.spring.BeanPostProcessorTest$Animal
16:24:04.891 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'panda'
- 2. InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation:实例化之前: panda, class site.xiaokui.db.spring.BeanPostProcessorTest$Animal
- 3. Animal init:国宝熊猫
- 5. InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation:实例化完成之后: panda, animal name is 国宝熊猫
- 6. InstantiationAwareBeanPostProcessor.postProcessProperties:开始注入/填充属性: panda, animal name is 国宝熊猫, PropertyValues: length=0
- 7. BeanPostProcessor.postProcessBeforeInitialization:BeanPostProcessor:实例化完成,初始化开始: panda, animal name is 国宝熊猫
- 9. BeanPostProcessor.postProcessAfterInitialization:初始化结束

# 初始化 TestBean
- 2. InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation:实例化之前: testBean, class site.xiaokui.db.spring.BeanPostProcessorTest$TestBean
- 3. SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors:确定候选构造器: testBean, class site.xiaokui.db.spring.BeanPostProcessorTest$TestBean
- 5. InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation:实例化完成之后: testBean, animal name is null
- 6. InstantiationAwareBeanPostProcessor.postProcessProperties:开始注入/填充属性: testBean, animal name is null, PropertyValues: length=0
- 1. SmartInstantiationAwareBeanPostProcessor.predictBeanType:预测Bean类型: testBean, class site.xiaokui.db.spring.BeanPostProcessorTest$TestBean
- 1. SmartInstantiationAwareBeanPostProcessor.predictBeanType:预测Bean类型: testBean, class site.xiaokui.db.spring.BeanPostProcessorTest$TestBean
- 7. BeanPostProcessor.postProcessBeforeInitialization:BeanPostProcessor:实例化完成,初始化开始: testBean, animal name is 国宝熊猫
- 8.1 PostConstruct:已经激活Aware接口且bean所有属性已设置完毕
- 8.2 InitializingBean.afterPropertiesSet:get a animal:国宝熊猫
- 9. BeanPostProcessor.postProcessAfterInitialization:初始化结束
animal name is 国宝熊猫

三、全流程总结

文字版简述,具体如下:

1、main方法启动

main方法作为入口,触发Spring Boot的启动加载

2、Spring Boot加载

Spring Boot加载具体可以分为以下几块:

  1. 发布 ApplicationStarting 事件,触发相应事件监听器的处理逻辑,主要为 日志框架的启动、组件提前初始化
  2. 初始化 ConfigurableEnvironment,读取系统属性和环境变量
  3. 发布 EnvironmentPrepared 事件,触发相应事件监听器的处理逻辑,主要为 外部配置文件的加载、初始化日志框架、设置日志颜色
  4. 打印 Banner,这在Spring Boot中是一个独立的环节
  5. 根据当前创建对应的 WebApplication,可选 AnnotationConfigServletWebServerApplicationContext、AnnotationConfigReactiveWebServerApplicationContext、AnnotationConfigApplicationContext
  6. 为刚刚创建的 WebApplication 做一些准备工作,主要包含 Environment 的设置、applyInitializers、发布 contextPrepared/contextLoaded 事件
  7. 刷新 WebApplication
  8. callRunners,Spring完全启动后回调特定接口方法

3、刷新WebApplication

其中,刷新 WebApplication 又可以分为以下几块:

  1. 准备刷新,主要是 打印刷新开始日志、对系统属性及环境变量的初始化及验证
  2. 获取 BeanFactory,这里是直接返回一个初始化好的 DefaultListableBeanFactory,来自 GenericApplicationContext#getBeanFactory
  3. 开始对 BeanFactory 进行一系列功能的设置,确保具有Spring需要一系列功能,例如 支持SPEL、Aware接口、ignoreDependency
  4. BeanFactory 后处理,主要为 增加ServletContextAwareProcessor、过滤特定Web Aware、注册web专有scope、设置全局属性
  5. invokeBeanFactoryPostProcessors,此步骤最重要的是两个接口、一个关键类和多个注解。
    1. BeanDefinitionRegistryPostProcessor 接口,负责扫描处理所有BeanDefinition,接口方法为 postProcessBeanDefinitionRegistry
    2. BeanFactoryPostProcessor 接口,负责对BeanFactory做定制处理,接口方法为 postProcessBeanFactory
    3. 关键类为 ConfigurationClassPostProcessor,有且只有这么一个系统内置关键类
    4. ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 方法会扫描所有 @Component@Configuration,并且对 @Bean、@Import、@ComponentScans 提供了支持
    5. main方法所在类被注解 @SpringBootApplication 标记,而 @SpringBootApplication 本质上一个 @Configuration@Configuration 本质是一个 @Component
    6. @SpringBootApplication 注解本身又被 @ComponentScan@EnableAutoConfiguration 标记,而 @EnableAutoConfiguration底层是 @Import
    7. 综上所述,postProcessBeanDefinitionRegistry 方法会扫描所有Spring自动注入bean(含各种功能组件starter的自动装配bean)、用户包路径自定义bean
    8. postProcessBeanFactory 方法主要是为 @Configuration 提供代理增强
  6. registerBeanPostProcessors,扫描并注册前面出现的一系列 BeanPostProcessors,供生产bean时使用
  7. onRefresh,此步将触发 Tomcat web容器的初始化
    1. Tomcat Bean 是Spring Boot自动装配注入进去的,其后置会引发初始化 DispatcherServlet Bean 的初始化。
    2. 执行 DispatcherServlet 静态代码块,读取Spring默认web组件配置
    3. 启动 Tomcat,开始监听端口响应请求
  8. 完成刷新,包括一系列缓存的清楚、事件发布、配置冻结,最后也是最重要的,实例化所有非惰性加载的bean

4、web环境初始化

在Tomcat容器启动后,第一个请求将触发DispatcherServlet的初始,大致流程如下:

  1. Tomcat响应请求,将其转发到DispatcherServlet,这个会先触发父类 HttpServletBeaninit 初始化方法
  2. init 方法包含了web环境的刷新,主要是初始化各种web必须组件,如 HandlerMappings、HandlerExceptionResolvers、ViewResolvers 等
  3. 而后 DispatcherServlet 完成初始化,Tomcat将请求转发给 DispatcherServlet.doService 方法(所有get、post方法的总代理)
  4. 继续响应请求

四、总结

纸上得来终觉浅,绝知此事须躬行。花点时间,跟下代码和日志,你也会有自己的理解。

总访问次数: 14次, 一般般帅 创建于 2024-01-17, 最后更新于 2024-11-17

进大厂! 欢迎关注微信公众号,第一时间掌握最新动态!