1. 前言

最后接触java的接口服务是servlet,最根底要把握的就是servlet的生命周期。当初都是基于springboot开发后盾接口,spring框架的复杂度远远高于原始的servlet,弄清楚spring中bean的生命周期,有利于咱们对其框架的熟练掌握。

2. spring容器加载

springboot的启动类中,都会执行SpringApplication.run办法。在创立上下文环境之后,最外围的办法就是refreshContext,对上下文环境进行初始化操作,本段就着重阐明这一过程。

2.1. refreshContext全过程

    @Override    public void refresh() throws BeansException, IllegalStateException {        synchronized (this.startupShutdownMonitor) {            /**             * 筹备环境             * 1. 记录容器的启动工夫startupDate,标记容器为激活             * 2. 初始化上下文环境如文件门路信息             * 3. 验证必填属性是否填写             */            prepareRefresh();            /**             * 通知子类去刷新beanFactory             * 这步实现后配置文件就解析成一个个beanDefination,注册到BeanFactory(然而未被初始化,仅将信息写到了beanDefination的map中)             */            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();            /**             * 设置beanFactory类加载器,增加多个beanPostProcesser             */            prepareBeanFactory(beanFactory);            try {                /**                 * 容许子类上下文中对beanFactory做前期解决                 */                postProcessBeanFactory(beanFactory);                /**                 * 执行 context 中注册的 BeanFactoryPostProcessor中的postProcessBeanFactory() 办法                 * 1. BeanFactoryPostProcessor 是 bean 属性解决容器。即治理 bean工厂中的BeanDefinition                 * 2. BeanDefinition在 spring mvc中就是xml文件中对应的bean标签(留神,是标签,而不是实在的 java bean)                 */                invokeBeanFactoryPostProcessors(beanFactory);                /**                 * 注册 BeanPostProcessor 的实现类                 * 1. BeanPostProcessor接口蕴含两个办法:postProcessBeforeInitialization 和 postProcessAfterInitialization                 * 2. 这里只是注册,两个办法理论别离在 Bean初始化之前和初始化之后失去执行                 */                registerBeanPostProcessors(beanFactory);                /**                 * 初始化ApplicationContext的MessageSource,MessageSource是国际化相干的接口                 */                initMessageSource();                /**                 * 初始化ApplicationContext事件播送器                 */                initApplicationEventMulticaster();                // 初始化子类非凡bean(钩子办法)                onRefresh();                /**                 * 注册事件监听器                 */                registerListeners();                /**                 * 初始化所有的单例java bean(不蕴含懒加载的类)                 */                finishBeanFactoryInitialization(beanFactory);                /**                 * 播送事件,ApplicationContext初始化实现                 */                finishRefresh();            } catch (BeansException ex) {                ....................            }        }    }

2.2. BeanDefinition

BeanDefinition 是 spring bean 的建模对象,即把一个bean实例化进去的模型对象。有人会问把一个bean实例化进去有Class就行了啊,Class也就是咱们通常说的类对象,就是一个一般对象的建模对象,那么为什么spring不能用Class来建设bean呢?很简略,因为Class无奈实现bean的形象,比方bean的作用域,bean的注入模型,bean是否是懒加载等等信息,Class是无奈形象进去的,故而须要一个BeanDefinition类来形象这些信息,以便于spring可能完满的实例化一个bean。

spring扫描到某个bean的类时,除了要存储类名、结构器等Class的根底信息以外,还要存储scope,lazy,dependsOn等spring的属性。BeanDefintion是一个类,专门用来存储上述bean中的各种属性。因而当spring扫描到一个合乎规定的类时,首先是实例化一个BeanDefinition的对象,并且把依据类的类名生成一个bean的名字,继而以beanName为key,BeanDefinition对象为value,寄存在一个map中。

值得注意的是,这里都是讲在扫描bean后,BeanDefinition的实例化,以及放入BeanDefinition的map中。还没有讲到Bean的实例化和装载。

BeanDefinition 的属性办法如下:

  • String: getBeanClassName: 返回以后bean definition定义的类名
  • ConstructorArgumentValues: getConstructorArgumentValues:返回bean的结构函数参数
  • String[]: getDependsOn:返回以后bean所依赖的其余bean的名称
  • String: getFactoryBeanName: 返回factory bean的名称
  • String: getFactoryMethodName: 返回工厂办法的名称
  • BeanDefinition: getOriginatingBeanDefinition: 返回原始的BeanDefinition,如果不存在返回null
  • String: getParentName: 返回以后bean definition的父definition的名字
  • MutablePropertyValues: getPropertyValues: 返回一个用于新的bean实例上的属性值
  • String: getScope: 返回以后bean的指标范畴
  • boolean: isAbstract: 以后bean是否是abstract,意味着不能被实例化
  • boolean: isLazyInit: bean是否是提早初始化
  • boolean: isPrimary: bean是否为主动拆卸的次要候选bean
  • boolean: isPrototype: bean是否是多实例
  • boolean: isSingleton: bean是否是单例
  • void: setAutowiredCandidate(boolean): 设置bean是否对其余bean是主动拆卸的候选bean
  • void: setBeanClassName(String): 指定bean definition的类名
  • void: setDependsOn(String ...): 设置以后bean初始化所依赖的beans的名称
  • void: setFactoryBeanName(String): 如果factory bean的名称
  • void: setFactoryMethodName(String): 设置工厂的办法名
  • void: setLazyInit(boolean lazyInit): 设置是否提早初始化
  • void: setParentName(String): 设置父definition的名称
  • void: setPrimary(boolean): 设置是否次要的候选bean
  • void: setScope(String): 设置bean的范畴,如:单例,多实例

2.3. BeanFactoryPostProcessor

BeanFactoryPostProcessor是实现spring容器性能扩大的重要接口,例如批改BeanDefinition,实现bean动静代理等。很多框架都是通过此接口实现对spring容器的扩大,例如mybatis与spring集成时,只定义了mapper接口,无实现类,接口也没有增加@Component等注解,但spring却能够实现主动注入,也是基于BeanFactoryPostProcessor接口来实现的。

BeanFactoryPostProcessor.java

@FunctionalInterfacepublic interface BeanFactoryPostProcessor {    void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;}

前文说到BeanDefinition在实例化之后,被放入BeanDefinition map中,而BeanFactoryPostProcessor就是在BeanDefinition map初始化实现后,Bean实例构造方法执行之前执行的。

BeanFactoryPostProcessor的次要作用是,开发者能够批改容器中所有BeanDefinition的信息,接口办法的入参是ConfigurrableListableBeanFactory,应用该参数,能够获取到相干bean的定义信息。但 相对不容许进行bean实例化相干的操作!因为中spring加载机制中,BeanFactoryPostProcessor是在Bean构造方法之前执行的,如果这个时候提前实例化bean,很可能会一连串的问题。

如:在接口用通过configurableListableBeanFactory.getBean(“user”),获取User类的bean,实际上即实例化了User的bean。会导致在后续其余节点代码中,无奈注入User的bean实例。

2.4. BeanPostProcessor

如果说BeanFactoryPostProcessor是对BeanDefinition的扩大解决,那么BeanPostProcessor更多的是对Bean的扩大解决。BeanPostProcessor的触发工夫是在 Bean的实例化之后(执行了构造方法,并且对属性进行了赋值),在Bean的init办法执行之前(@PostConstruct注解办法、InitializeBean接口办法、@Bean中initMethod办法)

BeanPostProcessor.java

public interface BeanPostProcessor {    @Nullable    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {        return bean;    }    @Nullable    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {        return bean;    }}

BeanPostProcessor接口中定义两个办法,依据名字能够揣测,postProcessBeforeInitialization在Bean的init办法之前执行,postProcessAfterInitialization在Bean的init办法之后执行。这点很好的体现了spring的AOP思维,能够了解为BeanPostProcessor是对Bean的init办法执行前后,做了一层切面拦挡。

有一个实现Spring aop 的BeanPostProcessor 叫 AnnotationAwareAspectJAutoProxyCreator。在postProcessBeforeInitialization或者postProcessAfterInitialization办法中,对对象进行判断,看他需不需要织入切面逻辑,如果须要,那我就依据这个对象,生成一个代理对象,而后返回这个代理对象,那么最终注入容器的,天然就是代理对象了。

2.5. finishBeanFactoryInitialization

该办法会实例化所有残余的非懒加载单例 bean。值得注意的是“所有残余的”,就是有一些非凡的bean,这该办法之前就曾经加载了,如:

  1. 一些spring容器外部的bean;
  2. 实现了 BeanFactoryPostProcessor 接口的bean;
  3. 实现了 BeanPostProcessor 接口的 bean(然而这些bean会在这个办法中触发)。

其余的非懒加载单例 bean 都会在这个办法中被实例化,并且 BeanPostProcessor 的触发也是在这个办法中。

3. Bean的生命履历

基于spring的refresh过程,咱们把对于bean的局部拎进去,就造成了上面的bean的加载过程:

  1. spring基于@ComponentScan等注解扫描到bean,并将每个bean实例化成蕴含bean各种属性的BeanDefinition的对象,放入beanDefinitionMap中。
  2. spring 中的 bean 简略分为:非凡bean和一般bean,beanFactory理论会先实例化非凡bean。
  3. 实现BeanFactoryPostProcessor接口的就是一种非凡bean,在beanDefinitionMap加载后触发,能够自定义实现类,对其中的BeanDefinition进行批改。
  4. construct过程。BeanFactory 执行getBean办法生产其余的一般bean(调用类的构造方法,或FactoryBean的getObject办法,以及@Bean注解的办法)。
  5. 此时bean获取会受三级缓存(singletonFactories、earlySingletonObjects、singletonObjects)影响,如earlySingletonObjects会提前曝光尚未populate属性数据的单例对象,可解决循环依赖问题。
  6. populate过程。设置bean的依赖关系(基于属性注入)以及属性值。
  7. 对于实现BeanPostProcessor接口的类,执行接口中的postProcessBeforeInitialization 办法。
  8. initialze过程。执行bean的各种初始化办法,initialze办法的优先级如下:(1)@PostConstruct指定的办法 -> (2)InitializingBean接口的afterPropertiesSet()办法 -> (3)@Bean中initMethod指定的办法
  9. 对于实现BeanPostProcessor接口的类,执行接口中的postProcessAfterInitialization 办法。
  10. destroy过程,容器销毁,执行bean的各种销毁办法,destroy办法的优先级如下:(1)@PostDestroy指定的办法 -> (2)DisposableBean接口的destroy()办法 -> (3)@Bean中destroyMethod指定的办法

在spring bean生命周期中,网上有人用Bean的“初始化”、“实例化”等名字,很容易搞混,所以我应用了下列几个英文单词,感觉更能表白这些过程:

  • construct:是对象创立的过程。比方应用构造方法new对象。
  • populate:是为对象中的属性赋值的过程,包含@Autowired等依赖注入,@Value的赋值等。
  • initialize:执行初始化办法。

其实并非只有在populate时才会注入依赖,还是要取决于属性的注入形式:基于属性注入、setter注入和结构器注入等。如果是基于结构器注入,在construct过程中,就会导入依赖。

另外咱们中应用@Value、@ConfigurationProperties等注解赋值,也是属于populate过程的操作。

4、bean相干办法

对于上述对于bean生命周期的介绍,咱们写个demo,一一实现相干的办法,亲眼看看他们的加载过程。

4.1、BeanFactoryPostProcessor

@Slf4j@Componentpublic class BeanFactoryPostProcessorImpl implements BeanFactoryPostProcessor {    /**     * getBean 是获取Object对象,getBeanDefinition 是获取Class类     * 能够批改BeanDefinition     * 但getBean办法不要用,会导致提前加载bean,bean实例化错乱     * @param beanFactory     */    @Override    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {        log.warn("实现 BeanFactoryPostProcessor 接口:开始了!");        Arrays.stream(beanFactory.getBeanDefinitionNames())                .filter(beanName -> User.USER_BEAN_NAME.equals(beanName))                .forEach(beanName -> {                    BeanDefinition beanDefinition=beanFactory.getBeanDefinition(beanName);                    beanDefinition.getPropertyValues().add("name","Kerry");                    log.warn("BeanFactoryPostProcessor:Bean name is " + beanName);                });    }}

次要是对 BeanDefinitionName 的批改,这里将对象的属性name的值设置为Kerry。

4.2、BeanPostProcessor

@Slf4j@Componentpublic class BeanPostProcessorImpl implements BeanPostProcessor {    /**     * Bean 初始化办法 执行前 调用     * @param bean     * @param beanName     * @return     * @throws BeansException     */    @Override    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {        if(User.USER_BEAN_NAME.equals(beanName)) {            log.warn("BeanPostProcessor-name:"+((User)bean).getName());            log.warn("实现 BeanPostProcessor 接口:postProcessBeforeInitialization(Object bean, String beanName),beanName=" + beanName);        }        return bean;    }    /**     * Bean 初始化办法 执行后 调用     * @param bean     * @param beanName     * @return     * @throws BeansException     */    @Override    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {        if(User.USER_BEAN_NAME.equals(beanName)) {            log.warn("实现 BeanPostProcessor 接口:postProcessAfterInitialization(Object bean, String beanName),beanName=" + beanName);        }        return bean;    }}

4.3、初始化和销毁办法

初始化和销毁两种办法往往是配套的,有上面三种,并且依照下列程序执行:

  1. @PostConstruct 和 @PreDestroy 注解润饰的办法,别离在初始化和销毁时执行。
  2. 实现 InitializeBean 接口的 afterPropertiesSet()办法,和实现 DisposableBean 接口的 destroy()办法,别离在初始化和销毁时执行。
  3. @Bean 中initMethod属性指定的办法,和destroyMethod属性指定的办法,别离在初始化和销毁时执行。

咱们在User类中定义了这些初始化和销毁办法,因为还要测试依赖注入程序,也定义了Type类的办法。

User.java

@Slf4jpublic class User implements InitializingBean, DisposableBean {    public final static String USER_BEAN_NAME="user";    //配置文件中,注入的值为 demoName    @Value("${params.user.name}")    private String name;    private Integer age=1;    @Autowired    private Type type;    @Override    public String toString(){        return "My name is "+name+",I'm "+age+"years old.";    }    /**     * 构造方法     * 1、默认构造方法     * 2、重载构造方法     */    public User(){        log.warn("构造方法:public User()");    }    /**     * 初始化     * 1、注解:@PostConstruct 的办法     * 2、实现 InitializeBean 接口:afterPropertiesSet()     * 3、@Bean 中指定的 initMethod     */    @PostConstruct    public void postConstruct(){        log.warn("注解:@PostConstruct 的办法");    }    @Override    public void afterPropertiesSet(){        log.warn("实现 InitializeBean 接口:afterPropertiesSet()");    }    public void initMethod(){        log.warn("@Bean 中指定的 initMethod ");    }    /**     * 销毁     * 1、注解:@PreDestroy 的办法     * 2、实现 DisposableBean 接口:destroy()     * 3、@Bean 中指定的 destroyMethod     */    @PreDestroy    public void preDestroy(){        log.warn("注解:@PreDestroy 的办法");    }    @Override    public void destroy(){        log.warn("实现 DisposableBean 接口:destroy()");    }    public void destroyMethod(){        log.warn("@Bean 中指定的 destroyMethod");    }        public void setName(String name) {        log.warn("User.setName办法:"+name);        this.name = name;    }}

Type.java

@Component@Data@Slf4jpublic class Type implements InitializingBean {    private String typeCode;    public Type(){       log.warn("构造方法:public Type()");    }    @Override    public void afterPropertiesSet(){        log.warn("Type:实现 InitializeBean 接口:afterPropertiesSet()");    }}

BeanConfig.java

@Configurationpublic class BeanConfig {        @Bean(initMethod = "initMethod",destroyMethod = "destroyMethod")    public User user(){        return new User();    }}

4.4. 后果验证

还记得咱们在BeanFactoryPostProcessorImpl中批改了name的值吗?咱们先把批改的代码正文掉,执行之后的日志如下,确实依照后面的Bean生命周期加载的:

p.k.e.s.c.BeanFactoryPostProcessorImpl   : 实现 BeanFactoryPostProcessor 接口:开始了!p.k.e.s.c.BeanFactoryPostProcessorImpl   : BeanFactoryPostProcessor:Bean name is userp.k.exercise.springexercise.pojo.User    : 构造方法:public User()p.k.exercise.springexercise.pojo.Type    : 构造方法:public Type()p.k.exercise.springexercise.pojo.Type    : Type:实现 InitializeBean 接口:afterPropertiesSet()p.k.e.s.config.BeanPostProcessorImpl     : BeanPostProcessor-name:demoNamep.k.e.s.config.BeanPostProcessorImpl     : 实现 BeanPostProcessor 接口:postProcessBeforeInitialization(Object bean, String beanName),beanName=userp.k.exercise.springexercise.pojo.User    : 注解:@PostConstruct 的办法p.k.exercise.springexercise.pojo.User    : 实现 InitializeBean 接口:afterPropertiesSet()p.k.exercise.springexercise.pojo.User    : @Bean 中指定的 initMethod p.k.e.s.config.BeanPostProcessorImpl     : 实现 BeanPostProcessor 接口:postProcessAfterInitialization(Object bean, String beanName),beanName=userp.k.exercise.springexercise.pojo.User    : 注解:@PreDestroy 的办法p.k.exercise.springexercise.pojo.User    : 实现 DisposableBean 接口:destroy()p.k.exercise.springexercise.pojo.User    : @Bean 中指定的 destroyMethod

当初把BeanFactoryPostProcessorImpl中的正文放开,日志变了:

p.k.e.s.c.BeanFactoryPostProcessorImpl   : 实现 BeanFactoryPostProcessor 接口:开始了!p.k.e.s.c.BeanFactoryPostProcessorImpl   : BeanFactoryPostProcessor:Bean name is userp.k.exercise.springexercise.pojo.User    : 构造方法:public User()p.k.exercise.springexercise.pojo.Type    : 构造方法:public Type()p.k.exercise.springexercise.pojo.Type    : Type:实现 InitializeBean 接口:afterPropertiesSet()p.k.exercise.springexercise.pojo.User    : User.setName办法:Kerryp.k.e.s.config.BeanPostProcessorImpl     : BeanPostProcessor-name:Kerryp.k.e.s.config.BeanPostProcessorImpl     : 实现 BeanPostProcessor 接口:postProcessBeforeInitialization(Object bean, String beanName),beanName=userp.k.exercise.springexercise.pojo.User    : 注解:@PostConstruct 的办法p.k.exercise.springexercise.pojo.User    : 实现 InitializeBean 接口:afterPropertiesSet()p.k.exercise.springexercise.pojo.User    : @Bean 中指定的 initMethod p.k.e.s.config.BeanPostProcessorImpl     : 实现 BeanPostProcessor 接口:postProcessAfterInitialization(Object bean, String beanName),beanName=userp.k.exercise.springexercise.pojo.User    : 注解:@PreDestroy 的办法p.k.exercise.springexercise.pojo.User    : 实现 DisposableBean 接口:destroy()p.k.exercise.springexercise.pojo.User    : @Bean 中指定的 destroyMethod

能够看到如果咱们在BeanFactoryPostProcessor接口中通过BeanDefinition 的PropertyValue 设置属性值,其实只是批改了该属性的setter办法,而真正执行该办法,还是在populate阶段,而非BeanFactoryPostProcessor执行阶段。