T O P

[资源分享]     Spring Bean 的生命周期

  • By - 楼主

  • 2021-03-03 02:00:10
  • 除了使用阶段外,Spring 将 bean 的生命周期定义为实例化、属性填充、初始化和销毁四个阶段,并为每个阶段提供了多个拓展点用于自定义 bean 的创建过程。这篇文章介绍了 bean 的生命周期和其各个拓展点,通过图示生动的展示、并结合一个实例来演示全过程。

    Spring 生命周期

    graph LR ClassLoad(类加载) --> Instantiation[实例化] Instantiation --> Populate[属性填充] Populate --> Initialization[初始化] Initialization --> Using(使用) Using --> Destruction[销毁]

    上图中,每个箭头上都有 Spring 提供的拓展点。类加载不是 bean 生命周期的一部分,保留在图上纯粹是因为要提供第一个右向的箭头,而使用阶段也不在讨论范围内,故这两个采用圆角矩形。

    拓展点的类型

    Spring 提供的拓展点可以分为:

    • 用于单个 bean 感知自身过程的专用拓展点:下方出现的、以 Aware 结尾为名的接口,org.springframework.beans.factory.InitializingBean 接口和 org.springframework.beans.factory.DisposableBean 接口,这些接口都只定义了一个函数。bean 通过实现这些接口、重写其中的函数来实现拓展点。Spring 容器会在适当的时候调用这些函数。

    • 用于所有普通 bean 初始化的通用拓展点:位于 org.springframework.beans.factory.config 包的 BeanPostProcessorInstantiationAwareBeanPostProcessorDestructionAwareBeanPostProcessor 接口,这些接口中定义了多个拓展点,使用时需要定义一个专门的类实现接口、重写必要的函数。Spring 容器会将这些实现类优先注册为 bean,待它们初始化完成后再初始化普通的 bean,在每个普通 bean 注册时,Spring 容器都会尝试调用所有已注册的通用拓展点。

      classDiagram BeanPostProcessor <|-- InstantiationAwareBeanPostProcessor BeanPostProcessor <|-- DestructionAwareBeanPostProcessor BeanPostProcessor: +postProcessBeforeInitialization() BeanPostProcessor: +postProcessAfterInitialization() InstantiationAwareBeanPostProcessor: +postProcessBeforeInstantiation() InstantiationAwareBeanPostProcessor: +postProcessAfterInstantiation() DestructionAwareBeanPostProcessor: +postProcessBeforeDestruction()

    1. 实例化

    创建 bean 对象实例的过程,包括使用工厂模式创建和调用构造函数。Spring 通过 InstantiationAwareBeanPostProcessor 接口在实例化前和后各提供了两个通用拓展点,加上对象实例化的过程,执行顺序如下:

    1. postProcessBeforeInstantiation:在普通 bean 对象实例化开始之前调用
    2. 对象实例化
    3. postProcessAfterInstantiation:在普通 bean 对象实例化完成之后调用

    2. 属性填充

    如果对象中有 setter 函数,并通过配置元数据指定了注入的属性,Spring 容器会在这一步为其注入配置的值。完成属性填充后,Spring 通过 Aware(意为感知) 接口提供了十个专用拓展点,这些拓展点用于在 bean 自身内部、感知一些外部信息使用。调用顺序如下(下面提到的多个 Aware 接口中,前三个在 org.springframework.beans.factory 包中,4 ~ 9 在 org.springframework.context 包中,最后一个在 org.springframework.web.context 包中 ):

    1. BeanNameAware#setBeanName
    2. BeanClassLoaderAware#setBeanClassLoader
    3. BeanFactoryAware#setBeanFactory
    4. EnvironmentAware#setEnvironment
    5. EmbeddedValueResolverAware#setEmbeddedValueResolver
    6. ResourceLoaderAware#setResourceLoader(仅在 ApplicationContext 中有效)
    7. ApplicationEventPublisherAware#setApplicationEventPublisher(仅在 ApplicationContext 中有效)
    8. MessageSourceAware#setMessageSource(仅在 ApplicationContext 中有效)
    9. ApplicationContextAware#setApplicationContext(仅在 ApplicationContext 中有效)
    10. 如果是 Web 应用程序,还有 ServletContextAware#setServletContext(仅在 WebApplicationContext 中有效)

    Aware 拓展点结束之后,还有一个用于在初始化之前、进行属性校验的 InitializingBean#afterPropertiesSet 专用拓展点。

    3. 初始化

    初始化是指通过 bean 在将要工作前进行的最后准备工作,通常是 @BeaninitMethod 属性定义的函数执行的过程 。Spring 通过 BeanPostProcessor 接口在初始化之前和之后提供了两个通用拓展点,加上初始化函数执行顺序为:

    1. postProcessBeforeInitialization
    2. 自定义的初始化函数
    3. postProcessAfterInitialization

    4. 销毁

    销毁是指 bean 释放其占用的一些外部资源的过程,通常是 @Bean 注解的 destroyMethod 属性定义的销毁函数执行的过程。Spring 通过 DestructionAwareBeanPostProcessor#postProcessBeforeDestruction 的通用拓展点,再加上 DisposableBean#destroy 提供了的专用拓展点,三者执行顺序为:

    1. DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
    2. DisposableBean#destroy
    3. 自定义的销毁函数。

    实例演示

    一个简单的演示,实现了上文提到的 bean 生命周期全部的拓展点,通过日志打印的方式观察执行顺序来直观的感受。

    在一个 bean 中实现全部的专用拓展点

    SimpleBean 类

    /**
     * 一个简单的 bean 实例,实现了 Spring 提供的 bean 生命周期全拓展点,内部函数实现顺序即为 bean 生命周期中各个函数的调用顺序
     */
    @Slf4j(topic = "简单Bean")
    public class SimpleBean
            implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware,
            EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware,
            ApplicationEventPublisherAware, MessageSourceAware, ApplicationContextAware, InitializingBean, DisposableBean {
    
        private EmptyBean emptyBean;
    
        static {
            //类加载期间 logger 还没有初始化,使用标准输出
            System.out.printf("[%s] 简单Bean : SimpleBean 类加载 loaded%n", Thread.currentThread().getName());
        }
    
        public SimpleBean() {
            log.info("构造函数执行,创建实例");
        }
    
        @Autowired
        public void setEmptyBean(EmptyBean emptyBean) {
            this.emptyBean = emptyBean;
            log.info("setter 函数执行,装配了 {}", this.emptyBean);
        }
    
        /** 用于通知 bean 感知自身名称 */
        @Override
        public void setBeanName(String name) {
            log.info("bean 名称为 {}", name);
        }
    
        /** 用于通知 bean 感知加载自身的类加载器 */
        @Override
        public void setBeanClassLoader(ClassLoader classLoader) {
            log.info("类加载器是 {}", classLoader);
        }
    
        /** 用于通知 bean 感知创建自身的 bean 工厂 */
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            //BeanFactory 可能会重写 toString(),造成日志输出过多不便于查阅
            log.info("由 {}@{} 创建", beanFactory.getClass(), beanFactory.hashCode());
        }
    
        /** 设置该 bean 的运行环境信息 */
        @Override
        public void setEnvironment(Environment environment) {
            //environment.toString() 会将所有环境信息输出,造成日志输出过多不便于查阅
            log.info("运行的 JVM 型号是 {}", environment.getProperty("java.vm.name"));
        }
    
        /** 设置嵌入式配置解析器,可用于解析嵌入在应用程序包内的配置文件中的文本值 */
        @Override
        public void setEmbeddedValueResolver(StringValueResolver resolver) {
            //在 application.properties 中定义了 editor.name 信息
            log.info("作者是 {}", resolver.resolveStringValue("${editor.name}"));
        }
    
        /** 设置用于资源解析的解析器,可用于解析任意格式的资源 */
        @Override
        public void setResourceLoader(ResourceLoader resourceLoader) {
            log.info("资源解析器对象:{}", resourceLoader);
        }
    
        /** 设置事件发布器,与 Spring 提供的事件发布订阅机制有关 */
        @Override
        public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
            log.info("事件发布器对象:{}", applicationEventPublisher);
        }
    
        /** 设置消息原,可用于实现国际化 */
        @Override
        public void setMessageSource(MessageSource messageSource) {
            log.info("消息源对象:{}", messageSource);
        }
    
        /** 为当前 bean 传入 ApplicationContext 引用,可使用该容器引用获取其他 bean 的引用 */
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            log.info("应用程序上下文对象:{}", applicationContext.getDisplayName());
        }
    
        /** 在所有属性设置和 Aware 接口定义的行为都执行完成后,由 BeanFactory 调用,bean 可在此校验自身配置并最终初始化 */
        @Override
        public void afterPropertiesSet() {
            log.info("属性装配全部完成,校验无误,开始初始化");
        }
    
        /** 自定义的初始化方法 */
        public void initMethod() {
            log.info("自定义的初始化方法");
        }
    
        /** 容器销毁时调用 */
        @Override
        public void destroy() {
            log.info("容器即将关闭,销毁其中的 bean");
        }
    
        /** 自定义的销毁方法 */
        public void destroyMethod() {
            log.info("自定义的销毁方法");
        }
    
    }
    
    /** 一个空的 bean,用于在 SimpleBean 中进行 setter 注入 */
    @Component
    public class EmptyBean {
    }
    

    自定义三种类型的通用拓展点

    实例化处理器

    @Slf4j(topic = "自定义实例化处理器")
    @Component
    public class CustomInstantiationProcessor implements InstantiationAwareBeanPostProcessor {
    
        public CustomInstantiationProcessor() {
            log.info("InstantiationAwareBeanPostProcessor 在其他 bean 创建前就创建完成");
        }
    
        /** 其他 bean 实例化之前调用 */
        @Override
        public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
            if (beanClass.equals(SimpleBean.class)) {
                log.info("{} 即将实例化", beanName);
            }
            return null;
        }
    
        /** 其他 bean 实例化之后调用 */
        @Override
        public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
            if (bean instanceof SimpleBean) {
                log.info("{} 实例化完成", beanName);
            }
            return true;
        }
    
    }
    

    初始化处理器

    @Slf4j(topic = "自定义初始化处理器")
    @Component
    public class CustomInitializationProcessor implements BeanPostProcessor {
    
        public CustomInitializationProcessor() {
            log.info("BeanPostProcessor 在其他 bean 创建前就创建完成");
        }
    
        /** 其他 bean 初始化之前调用 */
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof SimpleBean) {
                log.info("{} 即将初始化", beanName);
            }
            return bean;
        }
    
        /** 其他 bean 初始化完成之后调用 */
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof SimpleBean) {
                log.info("{} 初始化完成", beanName);
            }
            return bean;
        }
    }
    

    销毁处理器

    @Slf4j(topic = "自定义销毁处理器")
    @Component
    public class CustomDestructionProcessor implements DestructionAwareBeanPostProcessor {
    
        public CustomDestructionProcessor() {
            log.info("DestructionAwareBeanPostProcessor 在其他 bean 创建前就创建完成");
        }
    
        /** 其他 bean 销毁之前调用 */
        @Override
        public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
            if (bean instanceof SimpleBean) {
                log.info("{} 即将销毁", beanName);
            }
        }
    
    }
    

    入口类

    @Slf4j
    @SpringBootApplication
    public class DemoApplication implements CommandLineRunner {
    
        private SimpleBean bean;
    
        @Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
        public SimpleBean simpleBean() {
            return new SimpleBean();
        }
    
        @Autowired
        public void setBean(SimpleBean bean) {
            this.bean = bean;
        }
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    
        @Override
        public void run(String... args) {
            log.info("{} 使用", bean.toString());
        }
    
    }
    

    结果解析


    1. JSR 250 定义的 @PostConstruct、 @PreDestory 和 @Component 共同使用定义 bean 时,自定义的初始化函数会在 InitializingBean#afterPropertiesSet,拓展点之前执行,后续查阅源码研究。

    本帖子中包含资源

    您需要 登录 才可以下载,没有帐号?立即注册