Spring作为以后Java最风行、最弱小的轻量级框架。Spring Bean的生命周期也是面试高频题,理解Spring Bean周期也能更好地帮忙咱们解决日常开发中的问题。程序员应该都晓得Spring的根底容器是ApplicationContext。应很多粉丝的强烈建议,本文我来剖析剖析 ApplicationContext中Bean的生命周期。ApplicationContext是顶层容器接口BeanFactory的实现类,因而,咱们理解了ApplicationContext的生命周期逻辑,也基本上理解了其余类型容器的生命周期逻辑。
1 Spring生命周期流程图
上面先来看一张Spring Bean残缺的生命周期流程图,下图形容的是从Spring容器初始化Bean开始直到Spring容器销毁Bean,所经验的要害节点。
从上图能够看出,Spring Bean的生命周期治理的基本思路是:在Bean呈现之前,先筹备操作Bean的BeanFactory,而后操作完Bean,所有的Bean也还会交给BeanFactory进行治理。在所有Bean操作筹备BeanPostProcessor作为回调。在Bean的残缺生命周期治理过程中,经验了以下次要几个步骤:
1.1 Bean创立前的筹备阶段
步骤1: Bean容器在配置文件中找到Spring Bean的定义以及相干的配置,如init-method和destroy-method指定的办法。
步骤2: 实例化回调相干的后置处理器如BeanFactoryPostProcessor、BeanPostProcessor、InstantiationAwareBeanPostProcessor等
1.2 创立Bean的实例
步骤3: Srping 容器应用Java反射API创立Bean的实例。
步骤4:扫描Bean申明的属性并解析。
1.3 开始依赖注入
步骤5:开始依赖注入,解析所有须要赋值的属性并赋值。
步骤6:如果Bean类实现BeanNameAware接口,则将通过传递Bean的名称来调用setBeanName()办法。
步骤7:如果Bean类实现BeanFactoryAware接口,则将通过传递BeanFactory对象的实例来调用setBeanFactory()办法。
步骤8:如果有任何与BeanFactory关联的BeanPostProcessors对象已加载Bean,则将在设置Bean属性之前调用postProcessBeforeInitialization()办法。
步骤9:如果Bean类实现了InitializingBean接口,则在设置了配置文件中定义的所有Bean属性后,将调用afterPropertiesSet()办法。
1.4 缓存到Spring容器
步骤10: 如果配置文件中的Bean定义蕴含init-method属性,则该属性的值将解析为Bean类中的办法名称,并将调用该办法。
步骤11:如果为Bean Factory对象附加了任何Bean 后置处理器,则将调用postProcessAfterInitialization()办法。
1.5 销毁Bean的实例
步骤12:如果Bean类实现DisposableBean接口,则当Application不再须要Bean援用时,将调用destroy()办法。
步骤13:如果配置文件中的Bean定义蕴含destroy-method属性,那么将调用Bean类中的相应办法定义。
2 代码实战演示
上面咱们用一个简略的Bean来演示并察看一下Spring Bean残缺的生命周期。
2.1 筹备Author类
1、首先是一个简略的Bean,调用Bean本身的办法和Bean级生命周期接口办法,为了不便演示,它实现了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这4个接口,同时增加2个init-method和destory-method办法,对应配置文件中<bean>的init-method和destroy-method。具体代码如下:
package com.tom.lifecycle;import lombok.Data;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.BeansException;import org.springframework.beans.factory.*;@Slf4j@Datapublic class Author implements BeanFactoryAware, BeanNameAware, InitializingBean, DisposableBean { private String name; private String address; private int age; private BeanFactory beanFactory; private String beanName; public Author() { log.info("【结构器】调用Tom类的结构器实例化"); } public void setName(String name) { log.info("【注入属性】name"); this.name = name; } public void setAddress(String address) { log.info("【注入属性】address"); this.address = address; } public void setAge(int age) { log.info("【注入属性】age"); this.age = age; } // 实现BeanFactoryAware接口的办法 public void setBeanFactory(BeanFactory beanFactory) throws BeansException { log.info("【BeanFactoryAware接口】调用setBeanFactory办法"); this.beanFactory = beanFactory; } // 实现BeanNameAware接口的办法 public void setBeanName(String beanName) { log.info("【BeanNameAware接口】调用setBeanName办法"); this.beanName = beanName; } // 实现DiposibleBean接口的办法 public void destroy() throws Exception { log.info("【DiposibleBean接口】调用destroy办法"); } // 实现InitializingBean接口的办法 public void afterPropertiesSet() throws Exception { log.info("【InitializingBean接口】调用afterPropertiesSet办法"); } // 通过<bean>的init-method属性指定的初始化办法 public void beanInit() { log.info("【init-method】调用<bean>的init-method属性指定的初始化办法"); } // 通过<bean>的destroy-method属性指定的初始化办法 public void beanDestory() { log.info("【destroy-method】调用<bean>的destroy-method属性指定的初始化办法"); }}
在配置Spring配置文件中退出如下内容:
<bean id="author" class="com.tom.lifecycle.Author" init-method="beanInit" destroy-method="beanDestory" scope="singleton" p:name="Tom" p:address="湖南长沙" p:age="18"/>
2.2 演示BeanFactoryPostProcessor的执行
1.创立GPBeanFactoryPostProcessor类,并实现BeanFactoryPostProcessor接口,具体代码如下:
package com.tom.lifecycle;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanDefinition;import org.springframework.beans.factory.config.BeanFactoryPostProcessor;import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;@Slf4jpublic class GPBeanFactoryPostProcessor implements BeanFactoryPostProcessor{ public GPBeanFactoryPostProcessor() { super(); log.info("调用BeanFactoryPostProcessor实现类结构器!!"); } public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { log.info("BeanFactoryPostProcessor调用postProcessBeanFactory办法"); BeanDefinition bd = configurableListableBeanFactory.getBeanDefinition("author"); bd.getPropertyValues().addPropertyValue("age", "16"); }}
2.在配置Spring配置文件中退出如下内容:
<bean id="beanFactoryPostProcessor" class="com.tom.lifecycle.GPBeanFactoryPostProcessor" />
3.编写测试类BeanLifeCycleTest,具体代码如下:
package com.tom.lifecycle;import lombok.extern.slf4j.Slf4j;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;@Slf4jpublic class BeanLifeCycleTest { public static void main(String[] args) { log.info("====== 开始初始化Spring容器 ========"); ApplicationContext factory = new ClassPathXmlApplicationContext("application-beans.xml"); log.info("====== 初始化Spring容器胜利 ========"); //获取Author实例 Author author = factory.getBean("author", Author.class); log.info(author.toString()); log.info("====== 开始销毁Spring容器 ========"); ((ClassPathXmlApplicationContext) factory).registerShutdownHook(); }}
4.运行后果
运行后果如下:
15:49:12.477 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - 调用BeanPostProcessor实现类结构器!!15:49:12.494 [main] INFO com.tom.lifecycle.Author - 【结构器】调用Tom类的结构器实例化15:49:12.527 [main] INFO com.tom.lifecycle.Author - 【注入属性】address15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【注入属性】age15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【注入属性】name15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【BeanNameAware接口】调用setBeanName办法15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【BeanFactoryAware接口】调用setBeanFactory办法15:49:12.528 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - BeanPostProcessor接口办法postProcessBeforeInitialization对属性进行更改15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【InitializingBean接口】调用afterPropertiesSet办法15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【init-method】调用<bean>的init-method属性指定的初始化办法15:49:12.528 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - BeanPostProcessor接口办法postProcessAfterInitialization对属性进行更改15:49:12.531 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - ====== 初始化Spring容器胜利 ========15:49:12.531 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - Author(name=Tom, address=湖南长沙, age=18, beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory@26653222: defining beans [beanPostProcessor,author]; root of factory hierarchy, beanName=author)15:49:12.531 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - ====== 开始销毁Spring容器 ========15:49:12.532 [Thread-0] INFO com.tom.lifecycle.Author - 【DiposibleBean接口】调用destroy办法15:49:12.533 [Thread-0] INFO com.tom.lifecycle.Author - 【destroy-method】调用<bean>的destroy-method属性指定的初始化办法
咱们看到,整个执行和咱们一开始绘制的流程图统一。然而为什么咱们要实现BeanFactoryPostProcessor接口呢?咱们进入到BeanFactoryPostProcessor的源码如下:
package org.springframework.beans.factory.config;import org.springframework.beans.BeansException;public interface BeanFactoryPostProcessor { void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;}
BeanFactoryPostProcessor接口只有一个postProcessBeanFactory()办法,BeanFactoryPostProcessor:在BeanFactory规范初始化之后能够进行批改。将加载所有Bean定义,然而还没有实例化Bean。这个办法容许从新笼罩或者增加属性甚至疾速的初始化bean。首次看到可能不晓得postProcessBeanFactory()到底是干嘛的。要想透彻了解这个办法的作用,上面来进入到BeanFactoryPostProcessor的源码,了解一下postProcessBeanFactory()的参数,咱们能够利用这些参数做一些操作。
通过参数来看,只有一个ConfigurableListableBeanFactory类,这个类的能够提供剖析、批改Bean定义和事后实例化单例的性能。咱们再进入到ConfigurableListableBeanFactory的源码中:
public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory { //疏忽被给定注入依赖类型 ,例如String void ignoreDependencyType(Class<?> var1); //略被给定注入依赖接口 。这个通常被应用由ApplicationContext去注册依赖,能够以多种形式实现。例如BeanFactory通过BeanFactoryAware,ApplicationContext 通过ApplicationContextAware。默认状况下,仅BeanFactoryAware接口是被疏忽,须要疏忽其余接口,调用此办法 void ignoreDependencyInterface(Class<?> var1); //注册一个特定类型依赖随同着相应的Autowired值。这个是筹备被用于应该能够Autowire而不是在这个工厂被定义的Bean的工厂/上下文援用。例如 将ApplicationContext类型的依赖项解析为Bean所在的ApplicationContext实例。留神~在一般的BeanFactory中没有注册这样的默认类型,甚至连BeanFactory接口自身都没有 void registerResolvableDependency(Class<?> var1, Object var2); //确认这个被指定的Bean是否是一个Autowire候选,将被注入到其余申明匹配类型的依赖的Bean中 boolean isAutowireCandidate(String var1, DependencyDescriptor var2) throws NoSuchBeanDefinitionException; //依据指定的beanName返回被注册的Bean定义,容许拜访其属性值和构造函数参数值(能够在BeanFactory前期解决期间被批改)。这个被返回的BeanDefinition对象不应该是正本而是原始在工厂被注册的。这意味着如果须要它能够被转换为更具体的实现类型。留神这个办法只能取得本地工厂BeanDefinition BeanDefinition getBeanDefinition(String var1) throws NoSuchBeanDefinitionException; //解冻全副Bean定义,给被注册的Bean定义发信号通知它们今后不再被批改和进一步后续解决。它容许Factory去踊跃缓存Bean定义元数据 void freezeConfiguration(); //返回该工厂的BeanDefinnition是否被解冻 boolean isConfigurationFrozen(); //确保所有非懒加载的单例Bean被实例化,包含FactoryBean void preInstantiateSingletons() throws BeansException;}
通过以上演示和剖析,咱们应该大略可能理解ConfigurableListableBeanFactory的作用,根本就都是对于Bean定义的操作。至此咱们还没有看到BeanPostProcessor 和InstantiationAwareBeanPostProcessor的调用。上面咱们把BeanPostProcessor 和InstantiationAwareBeanPostProcessor的实现补充上来,再看残缺的执行流程
2.3 实现BeanPostProcessor
创立GPBeanPostProcessor类,并实现BeanPostProcessor 接口,具体代码如下:
package com.tom.lifecycle;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanPostProcessor;@Slf4jpublic class GPBeanPostProcessor implements BeanPostProcessor { public GPBeanPostProcessor(){ log.info("调用BeanPostProcessor实现类结构器!!"); } public Object postProcessBeforeInitialization(Object o, String s) throws BeansException { log.info("BeanPostProcessor接口办法postProcessBeforeInitialization对属性进行更改"); return o; } public Object postProcessAfterInitialization(Object o, String s) throws BeansException { log.info("BeanPostProcessor接口办法postProcessAfterInitialization对属性进行更改"); return o; }}
ApplicationContext 能够在BeanDefinition中自动检测到实现了BeanPostProcessor的Bean,并且把这些Bean利用于随后的Bean创立。一般的BeanFactory容许对后处理器进行程序化注册,通过工厂利用于所有Bean创立。BeanPostProcessor接口中次要有两个办法:
办法名 | 解释 |
---|---|
postProcessBeforeInitialization | 在Bean实例化回调(例如InitializingBean的afterPropertiesSet 或者一个定制的init-method)之前利用此BeanPostProcessor |
postProcessAfterInitialization | 在bean实例化回调(例如InitializingBean的afterPropertiesSet 或者一个定制的init-method)之后利用此BeanPostProcessor |
2.4 实现InstantiationAwareBeanPostProcessor
创立GPInstantiationAwareBeanPostProcessor类,并实现InstantiationAwareBeanPostProcessorAdapter接口,具体代码如下:
package com.tom.lifecycle;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.BeansException;import org.springframework.beans.PropertyValues;import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;import java.beans.PropertyDescriptor;@Slf4jpublic class GPInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter { public GPInstantiationAwareBeanPostProcessor() { super(); log.info("调用InstantiationAwareBeanPostProcessorAdapter实现类结构器!!"); } // 接口办法、实例化Bean之前调用 @Override public Object postProcessBeforeInstantiation(Class beanClass,String beanName) throws BeansException { log.info("InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation办法"); return null; } // 接口办法、实例化Bean之后调用 @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { log.info("InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization办法"); return bean; } // 接口办法、设置某个属性时调用 @Override public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { log.info("InstantiationAwareBeanPostProcessor调用postProcessPropertyValues办法"); return pvs; }}
实现InstantiationAwareBeanPostProcessorAdapter的Bean之后,能够在实例化胜利之后,做一些校验或者补充些内容或者把Bean包装代理注入。实现InstantiationAwareBeanPostProcessorAdapter的Bean之后,不会影响容器失常解决每一个实例化的Bean,其子类仅仅只是依据须要笼罩父类的办法。
留神,只有在理论须要 InstantiationAwareBeanPostProcessor 性能时才举荐此基类。如果咱们所须要的只是简略的BeanPostProcessor性能,那么间接实现更简略的接口即可。
上面具体介绍一下InstantiationAwareBeanPostProcessorAdapter接口中的所有办法:
办法名 | 解释 |
---|---|
postProcessBeforeInstantiation | 在实例化指标Bean之前利用此BeanPostProcessor。这个返回的Bean兴许是一个代理代替指标Bean,无效地克制指标Bean的默认实例化。如果此办法返回一个非空对象,则Bean的创立过程将被短路。惟一的进一步解决被利用是BeanPostProcessor.postProcessAfterInitialization(java.lang.Object, java.lang.String)办法(扭转了Bean的生命周期实例化之后间接进入BeanPostProcessor.postProcessAfterInitialization)回调来自于配置好的BeanPostProcessors。这个回调将仅被利用于有Bean Class的BeanDefintions。特地是,它不会利用于采纳”factory-method“的Bean。后处理器能够实现扩大的SmartInstantiationAwareBeanPostProcessor接口,以便预测它们将返回的Bean对象的类型 |
postProcessPropertyValues | 在工厂将给定的属性值利用到给定的Bean之前,对给定的属性值进行后处理。容许查看全副依赖是否曾经全副满足,例如基于一个@Required在Bean属性的Setter办法上。还容许替换要利用的属性值,通常通过基于原始的PropertyValues创立一个新的MutablePropertyValues实例,增加或删除特定的值 |
postProcessAfterInitialization | 在Bean初始化回调(如InitializingBean的afterPropertiesSet或者定制的init-method)之后,利用这个BeanPostProcessor去给一个新的Bean实例。Bean曾经配置了属性值,返回的Bean实例可能曾经被包装。<br/>如果是FactoryBean,这个回调将为FactoryBean实例和其余被FactoryBean创立的对象所调用。这个post-processor能够通过相应的FactoryBean实例去查看决定是否利用FactoryBean或者被创立的对象或者两个都有。这个回调在一个由InstantiationAwareBeanPostProcessor短路的触发之后将被调用 |
2.5 批改配置文件
残缺的配置文件内容如下:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <bean id="beanPostProcessor" class="com.tom.lifecycle.GPBeanPostProcessor" /> <bean id="beanFactoryPostProcessor" class="com.tom.lifecycle.GPBeanFactoryPostProcessor" /> <bean id="instantiationAwareBeanPostProcessor" class="com.tom.lifecycle.GPInstantiationAwareBeanPostProcessor" /> <bean id="author" class="com.tom.lifecycle.Author" init-method="beanInit" destroy-method="beanDestory" scope="singleton" p:name="Tom" p:address="湖南长沙" p:age="18"/></beans>
2.6 运行后果
最初,咱们再次运行BeanLifeCycleTest测试类,看到如下运行后果:
15:56:20.030 [main] INFO com.tom.lifecycle.GPBeanFactoryPostProcessor - 调用BeanFactoryPostProcessor实现类结构器!!15:56:20.045 [main] INFO com.tom.lifecycle.GPBeanFactoryPostProcessor - BeanFactoryPostProcessor调用postProcessBeanFactory办法15:56:20.046 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - 调用BeanPostProcessor实现类结构器!!15:56:20.047 [main] INFO com.tom.lifecycle.GPInstantiationAwareBeanPostProcessor - 调用InstantiationAwareBeanPostProcessorAdapter实现类结构器!!15:56:20.051 [main] INFO com.tom.lifecycle.GPInstantiationAwareBeanPostProcessor - InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation办法15:56:20.052 [main] INFO com.tom.lifecycle.Author - 【结构器】调用Tom类的结构器实例化15:56:20.069 [main] INFO com.tom.lifecycle.GPInstantiationAwareBeanPostProcessor - InstantiationAwareBeanPostProcessor调用postProcessPropertyValues办法15:56:20.092 [main] INFO com.tom.lifecycle.Author - 【注入属性】address15:56:20.092 [main] INFO com.tom.lifecycle.Author - 【注入属性】age15:56:20.092 [main] INFO com.tom.lifecycle.Author - 【注入属性】name15:56:20.092 [main] INFO com.tom.lifecycle.Author - 【BeanNameAware接口】调用setBeanName办法15:56:20.092 [main] INFO com.tom.lifecycle.Author - 【BeanFactoryAware接口】调用setBeanFactory办法15:56:20.093 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - BeanPostProcessor接口办法postProcessBeforeInitialization对属性进行更改15:56:20.093 [main] INFO com.tom.lifecycle.Author - 【InitializingBean接口】调用afterPropertiesSet办法15:56:20.093 [main] INFO com.tom.lifecycle.Author - 【init-method】调用<bean>的init-method属性指定的初始化办法15:56:20.093 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - BeanPostProcessor接口办法postProcessAfterInitialization对属性进行更改15:56:20.093 [main] INFO com.tom.lifecycle.GPInstantiationAwareBeanPostProcessor - InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization办法15:56:20.097 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - ====== 初始化Spring容器胜利 ========15:56:20.098 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - Author(name=Tom, address=湖南长沙, age=16, beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory@26653222: defining beans [beanPostProcessor,beanFactoryPostProcessor,instantiationAwareBeanPostProcessor,author]; root of factory hierarchy, beanName=author)15:56:20.098 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - ====== 开始销毁Spring容器 ========15:56:20.099 [Thread-0] INFO com.tom.lifecycle.Author - 【DiposibleBean接口】调用destroy办法15:56:20.100 [Thread-0] INFO com.tom.lifecycle.Author - 【destroy-method】调用<bean>的destroy-method属性指定的初始化办法
3 Spring Bean生命周期运行时序图
最初咱们来看一下残缺的执行时序图: