zoukankan      html  css  js  c++  java
  • Spring中Bean的生命周期

    Spring生态目前发展很快,Spring、Spring Boot、Spring Cloud、Spring Data等等越来越丰富,并且迭代也很快。
    最近在找工作,面试过程中经常有问到Spring的基础知识,其中一个知识点就是Spring中Bean的生命周期。

    如果没有准备,突然问这道题有点答不上来。大概想的话就是先执行构造函数,执行一些接口方法(比如ContextAware、afterPropertiesSet),
    然后执行@PostConstruct标记的方法,最后执行destroy方法(如果有的话)。

    平常工作中:
    @PostConstruct有用到过,在类构造完成后用来执行一些自定义的初始化逻辑;
    afterPropertiesSet记得在Spring提供的类里经常有看到;
    ApplicationContextAware接口有在工具类用到,通过定义一个static变量和方法来获Spring的Context。

    找到一张图:

    写个Bean类来测试一下:

    package com.cdfive.learning.spring;
    
    import ch.qos.logback.classic.Level;
    import ch.qos.logback.classic.LoggerContext;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.BeanFactoryAware;
    import org.springframework.beans.factory.BeanNameAware;
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    
    /**
     * Test for Spring Bean lifecycle
     *
     * @author cdfive
     * @date 2019-04-09
     */
    @Component
    public class BeanLifecycle implements BeanNameAware, BeanFactoryAware, ApplicationContextAware
            , BeanPostProcessor, InitializingBean, DisposableBean {
    
        private static int STEP = 0;
    
        private String name;
    
        private Integer age;
    
        public static void main(String[] args) {
            // Close the log
            LoggerContext loggerContext= (LoggerContext) LoggerFactory.getILoggerFactory();
            ch.qos.logback.classic.Logger logger=loggerContext.getLogger("root");
            logger.setLevel(Level.OFF);
    
            // Create a Spring ApplicationContext and start
            AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext("com.cdfive.learning.spring");
            ctx.start();
    
            // Close the ApplicationContext
            ctx.close();
        }
    
        public BeanLifecycle() {
            print("constructor");
        }
    
        @PostConstruct
        public void postConstruct() {
            print("@PostConstruct");
        }
    
        @PreDestroy
        public void preDestroy() {
            print("@PreDestroy");
        }
    
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            print("BeanFactoryAware=>setBeanFactory");
        }
    
        @Override
        public void setBeanName(String s) {
            print("BeanNameAware=>setBeanName");
        }
    
        @Override
        public void destroy() throws Exception {
            print("DisposableBean=>destroy");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            print("InitializingBean=>afterPropertiesSet");
        }
    
        @Override
        public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
            print("BeanPostProcessor=>postProcessBeforeInitialization");
            return null;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
            print("BeanPostProcessor=>postProcessAfterInitialization");
            return null;
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            print("ApplicationContextAware=>setApplicationContext");
        }
    
        private static void print(String s) {
            System.out.println((++STEP) + "." + s);
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    }
    

    SpringBoot 2.0.5.RELEASE(即Spring 5.0.9.RELEASE)输出如下:

    1.constructor
    2.BeanNameAware=>setBeanName
    3.BeanFactoryAware=>setBeanFactory
    4.ApplicationContextAware=>setApplicationContext
    5.@PostConstruct
    6.InitializingBean=>afterPropertiesSet
    7.BeanPostProcessor=>postProcessBeforeInitialization
    8.BeanPostProcessor=>postProcessAfterInitialization
    9.BeanPostProcessor=>postProcessBeforeInitialization
    10.BeanPostProcessor=>postProcessAfterInitialization
    11.@PreDestroy
    12.DisposableBean=>destroy
    

    可以看到,基本跟那张图一致。

    不过有一点很奇怪的是BeanPostProcessor的postProcessBeforeInitialization、postProcessAfterInitialization执行了2次。

    尝试把版本降低点,改为1.5.10.RELEASE(即Spring 4.3.14.RELEASE)输出如下:

    1.constructor
    2.BeanNameAware=>setBeanName
    3.BeanFactoryAware=>setBeanFactory
    4.ApplicationContextAware=>setApplicationContext
    5.@PostConstruct
    6.InitializingBean=>afterPropertiesSet
    7.BeanPostProcessor=>postProcessBeforeInitialization
    8.BeanPostProcessor=>postProcessBeforeInitialization
    9.@PreDestroy
    10.DisposableBean=>destroy
    

    其中BeanPostProcessor的postProcessBeforeInitialization执行了2次,postProcessAfterInitialization没有执行。
    关于BeanPostProcessor还有待研究,暂时没有找到这个问题的原因.

    加深一下印象,基础知识确实应经常温习、总结。加油!

  • 相关阅读:
    CSP内容安全策略总结及如何抵御 XSS 攻击
    CORS跨域资源共享总结
    web安全总结
    小知识随手记(八)
    内存泄漏问题总结
    Vue中插槽slot的使用
    Git常用命令、及常见报错处理:You have not concluded your merge (MERGE_HEAD exists)、清理无效的远程追踪分支
    render函数、createElement函数与vm.$slots
    Redis集群(二):Redis的安装
    Shell命令_文件系统常用命令df、du
  • 原文地址:https://www.cnblogs.com/cdfive2018/p/10684164.html
Copyright © 2011-2022 走看看