1、Spring Bean 生命周期整体流程
Spring Bean 的生命周期,概括起来主要有四个阶段:
- 实例化(Instantiation):基于
BeanDefinition实例化一个 Bean ,此时 Bean 里的属性字段为 null 尚未赋值; - 属性赋值(Populate):为 Bean 里的属性字段赋值,包括解析
@Autowired等注入的属性字段; - 初始化(Initialization):将属性赋值后的 Bean 注册到 Spring 容器中,这里 Spring 提供了很多拓展接口,支持用户自定义 Bean 的初始化过程中做哪些操作,具体接口在第3小节介绍;
- 销毁(Destruction):销毁 Bean ,通常在 Spring 应用结束时调用。
2、面试说辞

Bean 生命周期的整个执行过程描述如下:
- Spring 启动,查找并加载需要被 Spring 管理的 Bean,对 Bean 进行实例化。
- 对 Bean 进行属性注入。
- 如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。
- 如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。
- 如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。
- 如果 Bean 实现了 BeanPostProcessor 接口,则 Spring 调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作。
- 如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法。
- 如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。
- 如果 Bean 实现了 BeanPostProcessor 接口,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization(),此处非常重要,Spring 的 AOP 就是利用它实现的。
- 此时,Bean 已经可以被应用系统使用了。
- 如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法销毁 Bean。
- 如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。
3、常用接口方法说明
对于上面的接口和方法,可以分为以下三大类:
- Bean自身的方法:比如构造函数、getter/setter 以及 Bean 中自定义的初始化方法(
init-method)和销毁方法(destory-method)等; - Bean直接实现的接口的方法:比如
BeanNameAware、BeanFactoryAware、InitializingBean、DisposableBean等方法,这些方法只对当前 Bean 生效; - 容器级生命周期的方法:这些接口的实现类是独立于 Bean 的,并且会注册到 Spring 容器中,在 Spring 容器创建任何 Bean 的时候,这些接口对应的方法都会发生作用。比如
InstantiationAwareBeanPostProcessor、BeanPostProcessor接口里的方法。Bean自身的方法和Bean直接实现的接口的方法都只对当前Bean起作用,但是容器级生命周期方法是对所有的bean都起作用的。
3.1 Bean自身的方法
Bean 的构造方法和 getter/setter 方法就不在介绍了,主要介绍一下通过@Bean(initMethod="initMethod", destroyMethod="destroyMethod")注解实现的初始化和销毁方法。
3.1.1 @Bean(initMethod=”initMethod”, destroyMethod=”destroyMethod”)
Spring 支持用户在 Bean 中自定义 Bean 的初始化和销毁时做的动作,即用户在 Bean 类中声明 public 的初始化和销毁方法,在公共的 BeanConfig 里通过@Bean注解创建这个 Bean 时,在@Bean注解里通过initMethod和destroyMethod参数将 Bean 类中自定义的初始化方法名和销毁方法名传入。
需要注意的是:
@Bean注解里initMethod参数指定的初始化 Bean 的方法,是在InitializingBean接口的afterPropertiesSet()方法执行之后再执行的;@Bean注解里destroyMethod参数指定的销毁 Bean 的方法,是在DisposableBean接口的destroy()方法执行之后再实行的。
@Bean(initMethod="initMethod", destroyMethod="destroyMethod")的Demo如下:
@Configuration@ComponentScans(value= {@ComponentScan("com.jerry.springbootstudy.lifecycle")})public class LifeCycleConfig {@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")public User user(){return new User();}}@Componentpublic class User implements {public void initMethod() {System.out.println("调用自定义的init方法初始化方法");}public void destroyMethod() {System.out.println("调用自定义的destroy方法销毁对象");}}
3.2 Bean直接实现的接口的方法
3.2.1 BeanNameAware接口
BeanNameAware接口是个函数式接口,只有一个方法void setBeanName(String s),通过该接口可以获取 Bean 的 name,demo 如下:
@Servicepublic class BizService implements BeanNameAware {private String beanName;@Overridepublic void setBeanName(String s) {this.beanName = s;}public String getBeanName() {return beanName;}}
BizService 实例可以通过调用getBeanName()方法获取当前 BizService 实例(Bean)的 beanName。
3.2.2 BeanFactoryAware接口
BeanFactoryAware接口也是一个函数式接口,只有一个方法void setBeanFactory(BeanFactory beanFactory) throws BeansException,通过该接口可以获取当前 Bean 对应的 beanFactory 的引用,demo 如下:
@Servicepublic class BizService implements BeanFactoryAware {private BeanFactory factory;@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.factory = beanFactory;}public BeanFactory getFactory() {return factory;}}
BizService 实例可以通过调用getFactory()方法获取当前 BizService 实例(Bean)对应的 beanFactory 的引用。
这里简要介绍一下 Spring 的 BeanFactory :Spring 提供了两种类型的IOC容器:BeanFactory 接口和 ApplicationContext 接口,二者的关系是 BeanFactory 接口是 ApplicationContext 接口的父父接口;
二者的区别在于:
- BeanFactory 是基础类型的Ioc容器,默认采取延迟初始化(懒加载)策略,所谓懒加载是指在容器初始化时并没有初始化容器中的bean,只有当程序需要访问其中一个被容器管理的对象时才会对bean进行初始化及其注入操作;
- ApplicationContext 在 BeanFactory 基础上构建,除了拥有 BeanFactory 的所有特性,它还支持事件发布、国际化信息的支持等。另外,ApplicationContext 管理的对象会在容器初始化的时候将其全部初始化。
3.2.3 ApplicationContextAware接口
ApplicationContextAware接口也是一个函数式接口,只有一个方法:void setApplicationContext(ApplicationContext applicationContext)throws BeansException,通过该接口可以获取 Spring 的上下文ApplicationContext 实例。Demo 如下: ```java
public class ApplicationContextUtil implements ApplicationContextAware{
private static ApplicationContext applicationContext;/*** 实现ApplicationContextAware接口的回调方法,设置上下文环境** @param applicationContext spring上下文对象* @throws BeansException 抛出spring异常*/@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {ApplicationContextUtil.applicationContext = applicationContext;}/*** @return ApplicationContext*/public static ApplicationContext getApplicationContext() {return applicationContext;}/*** 获取对象** @param name spring配置文件中配置的bean名或注解的名称* @return 一个以所给名字注册的bean的实例* @throws BeansException 抛出spring异常*/@SuppressWarnings("unchecked")public static <T> T getBean(String name) throws BeansException {return (T) applicationContext.getBean(name);}/*** 获取类型为requiredType的对象** @param clazz 需要获取的bean的类型* @return 该类型的一个在ioc容器中的bean* @throws BeansException 抛出spring异常*/public static <T> T getBean(Class<T> clazz) throws BeansException {return applicationContext.getBean(clazz);}/*** 如果ioc容器中包含一个与所给名称匹配的bean定义,则返回true否则返回false** @param name ioc容器中注册的bean名称* @return 存在返回true否则返回false*/public static boolean containsBean(String name) {return applicationContext.containsBean(name);}
}
获取到了 Spring 的上下文,意味着你可以通过实现类的实例获取 Spring 中的所有 Bean,或者判断当前上下文中是否含有指定名称的 Bean,但貌似实际项目中也没用到过。<a name="z8YGz"></a>### 3.2.4 InitializingBean接口`InitializingBean`接口也是一个函数式接口,只有一个方法:`void afterPropertiesSet() throws Exception`,通过该接口可以自定义 Bean 初始化时执行的操作。使用场景比如某功能需要在 Spring 启动(对应的就是你这个服务启动)的时候就执行,而不是通过自动注入 Bean 然后调用 Bean 的方法去触发,这个时候就可以将执行操作写在`afterPropertiesSet`方法里,IOC容器选择 ApplicationContext ,在 Spring 容器初始化的时候就初始化 Bean ,进而调用`afterPropertiesSet`方法里要执行的操作。<br />`InitializingBean`接口的简单demo如下:```java@Servicepublic class TestInitializingBean implements InitializingBean{private Logger logger = LoggerFactory.getLogger(TestInitializingBean.class);@Overridepublic void afterPropertiesSet() throws Exception {logger.info("开始工作......");logger.info("结束工作......");}}
这里说一下3.1.1中@Bean(initMethod="initMethod", destroyMethod="destroyMethod")中指定的初始化方法和InitializingBean接口的afterPropertiesSet方法的异同点:
- 相同点:功能都是 Bean 初始化时指定要执行的操作;
- 不同点:
@Bean注解中的init-method参数是通过反射执行的,而afterPropertiesSet是直接执行的,因此afterPropertiesSet的效率要高一些;- 执行顺序上
**afterPropertiesSet**先执行,**@Bean**注解中的**init-method**后执行。3.2.5 DisposableBean接口
DisposableBean接口也是一个函数式接口,只有一个方法void destroy(),在容器销毁的时候调用,且DisposableBean接口定义的destroy方法先执行,@Bean(initMethod="initMethod", destroyMethod="destroyMethod")中指定的销毁方法后执行。
3.3 容器级生命周期方法
3.3.1 BeanPostProcessor接口
该接口也叫后置处理器,作用是在 Bean 对象在实例化和依赖注入完毕后,在显示调用初始化方法(InitializingBean接口的afterPropertiesSet方法或自定义的init方法)的前后添加我们自己的逻辑。接口中有两个方法,如下:
public interface BeanPostProcessor {//实例化、依赖注入完毕,在调用显式的初始化之前完成一些定制的初始化任务。Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;//实例化、依赖注入、初始化完毕时执行定制的任务。Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;}
postProcessBeforeInitialization在InitializingBean接口的afterPropertiesSet方法或自定义的init-method方法执行前调用,postProcessAfterInitialization在InitializingBean接口的afterPropertiesSet方法或自定义的init-method方法执行后调用。
3.3.2 InstantiationAwareBeanPostProcessor接口
InstantiationAwareBeanPostProcessor接口是BeanPostProcessor的子接口,该接口跟 Bean 的实例化过程有关,接口中有3个方法(不包含父接口BeanPostProcessor里的2个方法),如下:
package org.springframework.beans.factory.config;public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;}
postProcessBeforeInstantiation |
该方法在目标对象实例化之前调用,该方法的返回值类型是Object。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(比如代理对象)。如果该方法返回为null,后续的方法都正常执行,如果该方法返回实例对象,则后续方法都不执行,直接执行BeanPostProcessor接口的postProcessAfterInitialization方法。 |
|---|---|
postProcessAfterInstantiation |
在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是 null。该方法的返回值是决定要不要调用postProcessPropertyValues方法的其中一个因素(因为还有一个因素是mbd.getDependencyCheck()),如果该方法返回 false,并且不需要 check,那么postProcessPropertyValues就会被忽略不执行;如果返回 true,postProcessProperties方法就会被执行。 |
postProcessProperties |
如果postProcessAfterInstantiation方法返回 false,该方法可能不会被调用。此时属性值还未被设置,但是可以通过postProcessProperties方法修改原本应该设置进去的属性值。 |
注意区分两个单词:
| 单词 | 含义 | 对应接口 |
|---|---|---|
| Instantiation | 表示实例化,对象还未生成 | InstantiationAwareBeanPostProcessor接口 |
| Initialization | 表示初始化,对象已经生成 | BeanPostProcessor接口 |
3.3.3 BeanFactoryPostProcessor接口
BeanFactoryPostProcessor接口也是一个函数式接口,只有一个方法postProcessBeanFactory,如下:
public interface BeanFactoryPostProcessor {void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;}
实现该接口,可以对beanDifinition进行修改。也就是说,Spring 允许BeanFactoryPostProcessor在容器实例化任何 Bean 之前读取配置元数据(beanDifinition),并可以根据需要进行修改,例如可以把 Bean 的 scope 从 singleton 改为 prototype,也可以把 property 的值给修改掉。可以同时配置多个BeanFactoryPostProcessor,并通过设置 order 属性来控制各个BeanFactoryPostProcessor的执行次序。注意:**BeanFactoryPostProcessor**的**postProcessBeanFactory**方法的执行顺序在**InstantiationAwareBeanPostProcessor**接口的**postProcessBeforeInstantiation**方法执行之前。
4、Spring生命周期Demo
根据第一节介绍的 Spring 生命周期详细的过程,设计 Demo 验证整个流程。
User:
@Componentpublic class User implements InitializingBean, BeanNameAware, DisposableBean {@Value("001")private String id;@Value("Jerry")private String name;public User() {System.out.println("3、调用构造函数");}public void initMethod() {System.out.println("9、调用自定义的init方法初始化方法");}public void destroyMethod() {System.out.println("12、调用自定义的destroy方法销毁对象");}public String getId() {return id;}public void setId(String id) {this.id = id;System.out.println("5、属性注入(id)");}public String getName() {return name;}public void setName(String name) {this.name = name;System.out.println("5、属性注入(name)");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("8、调用InitializingBean实例的afterPropertiesSet");}@Overridepublic void setBeanName(String name) {System.out.println("6、调用BeanNameAware接口的setBeanName方法");}@Overridepublic void destroy() throws Exception {System.out.println("11、调用DisposableBean接口的destroy方法");}}
User类中主要定义了 Bean 自身的方法和 Bean 实现的接口。
MyBeanFactoryPostProcessor:
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {System.out.println("1、调用BeanFactoryPostProcessor接口的postProcessBeanFactory方法,beanFactory: " + beanFactory);}}
MyBeanPostProcessor:
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("7、调用BeanPostProcessor接口的postProcessBeforeInitialization方法, bean:" + beanName);return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {User user = (User) bean;System.out.println("10、调用BeanPostProcessor接口的postProcessAfterInitialization方法, user id is: " + user.getId() + ", user name is: " + user.getName());return bean;}}
MyInstantiationAwareBeanPostProcessor:
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {System.out.println("2、调用InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation方法");return null;}@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {System.out.println("4、调用InstantiationAwareBeanPostProcessor接口的postProcessAfterInstantiation方法");return true;}@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {System.out.println("5、调用InstantiationAwareBeanPostProcessor接口的postProcessProperties方法");return pvs;}}
MyBeanFactoryPostProcessor、MyBeanPostProcessor和MyInstantiationAwareBeanPostProcessor是 Spring 容器级方法对应的接口的实现类。
LifeCycleConfig:
@Configuration@ComponentScans(value= {@ComponentScan("com.jerry.springbootstudy.lifecycle")})public class LifeCycleConfig {@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")public User user(){return new User();}@Beanpublic MyBeanPostProcessor myBeanPostProcessor() {return new MyBeanPostProcessor();}@Beanpublic MyBeanFactoryPostProcessor myBeanFactoryPostProcessor() {return new MyBeanFactoryPostProcessor();}@Beanpublic MyInstantiationAwareBeanPostProcessor myInstantiationAwareBeanPostProcessor() {return new MyInstantiationAwareBeanPostProcessor();}}
配置类,网上很多例子都是基于 Spring xml 配置文件的,但是现在开发项目中应该基本没有再用xml配置文件的了,都是用的 Config 类导入,这里 LifeCycleConfig 相当于一个主配置类(BeanConfig)。
LifeCycleConfigTest:
public class LifeCycleConfigTest {public static void main(String[] args) {// 基于配置类创建容器AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(LifeCycleConfig.class);// 从容器中获取beanObject user = ctx.getBean("user");// 销毁容器ctx.close();}}
注意这里要写成 main 函数启动的方式,而不是之前那种 Spirng 程序的启动方式,测试代码中通过AnnotationConfigApplicationContext生成 Spring 基于注解的上下文,再从上下文中获取 Bean,完成 user Bean 的初始化,并通过打印消息的方式代表对应的初始化方法已经执行了。为了打印结果对齐,没有采用log打印日志,而是通过System.out.println的方式将日志打印到控制台,启动 Spring 应用后,控制台的打印结果如下:
