一、执行流程
传统Java应用中,Bean的生命周期很简单,使用关键字new实例化Bean,不需要时,由Java GC回收。
Spring中Bean的生命周期较为复杂:Bean的定义-> Bean的初始化 -> Bean的使用 -> Bean的销毁。
Spring根据Bean的作用域来选择管理方式,对于singleton的Bean,Spring能够精准地知道该Bean何时被创建、何时初始化完成、何时被销毁;对于prototype作用域的Bean,Spring只负责创建,当容器创建Bean实例后,实例交由客户端代码管理,Spring容器不再跟踪其生命周期。
1.1、生命周期流程图
Bean的生命周期整个执行过程:
- Spring启动,查找并加载需要被Spring管理的Bean,并实例化Bean。
- 利用依赖注入完成Bean中所有属性值的配置注入。
- 如果Bean实现了BeanNameAware接口,则Spring调用Bean的setBeanName()方法传入当前Bean的id值。
- 如果Bean实现了BeanFactoryAware接口,则Spring调用setBeanFactory()方法传入当前工厂实例的引用。
- 如果Bean实现了ApplicationContextAware接口,则Spring调用setApplicationContext()方法传入当前ApplicationContext实例的引用。
- 如果Bean实现了BeanPostProcesor接口,则Spring调用该接口的预初始化方法postProcessBeforeInitialzation()对Bean进行加工操作,Spring AOP就是利用它实现的。
- 如果Bean实现了InitializingBean接口,则Spring将调用afterPropertiesSet()方法。
- 如果配置文件中通过init-method属性指定了初始化方法,则调用该初始化方法。
- 如果BeanPostProcessor和Bean关联,则Spring将调用该接口的初始化方法postProcessAfterInitialization()。此时,Bean已经在应用系统中使用了。
- 如果在中指定了该Bean的作用域为singleton,则将该Bean放入SpringIoC的缓存池中,触发Spring对该Bean的生命周期管理;如果作用域为prototype,则将该Bean交给调用者管理,Spring不管理该Bean。
- 如果Bean实现了DisposableBean接口,则Spring会调用destory()方法销毁Bean;如果在配置文件中指定了destory-method,Spring将调用该方法对Bean进行销毁。
Spring官方提供了3中法法实现初始化回调和销毁回调:
- 实现InitializingBean和DisposableBean接口
- 在XML中配置init-method和destory-method
- 使用@PostConstruct和@PreDestory注解
Bean中有杜仲生命周期回调方法时,优先级:注解 > 接口 > XML
二、初始化回调
2.1、使用接口
org.springframework.beans.factory.InitializingBean接口中存在方法:
void afterPropertiesSet() throws Exception;
可以在自己的类实现InitializingBean接口,重写afterPropertiesSet()方法,指定Bean初始化后需要执行的操作。
<bean id="test" class="com.jsonliu.bean.Test"></bean>
public class Test implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Test初始化后执行的操作");
}
}
2.2、配置XML
可以通过init-method属性指定Bean初始化后执行的方法
<bean id="test" class="com.jsonliu.bean.Test" init-method="init"></bean>
public class Test implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("实现InitializingBean接口的初始化方法");
}
public void init(){
System.out.println("XML中指定init-method的初始化方法");
}
}
2.3、使用注解
使用@PostConstruct注解标明该方法为Bean初始化后的方法
public class Test implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("实现InitializingBean接口的初始化方法");
}
public void init(){
System.out.println("XML中指定init-method的初始化方法");
}
@PostConstruct
public void initMethod(){
System.out.println("@PostConstruct注解指定的初始化方法");
}
}
三、销毁回调
3.1、使用接口
实现接口org.springframework.beans.factory.DisposableBean中方法:
void destroy() throws Exception;
该方法指定了Bean销毁后执行的方法
public class Test implements DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("实现了DisposableBean的销毁方法");
}
}
3.2、配置XML
可以通过destroy-method属性指定Bean销毁后执行的方法
<bean id="test" class="com.jsonliu.bean.Test" destroy-method="destroyMethod"></bean>
public class Test implements DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("实现了DisposableBean的销毁方法");
}
public void destroyMethod(){
System.out.println("XML中指定了destroy-method的销毁方法");
}
}
3.3、使用注解
使用@PreDestroy注解标明该方法为Bean销毁前执行的方法
public class Test implements DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("实现了DisposableBean的销毁方法");
}
public void destroyMethod(){
System.out.println("XML中指定了destroy-method的销毁方法");
}
@PreDestroy
public void destroyMethod2(){
System.out.println("@PreDestroy注解指定的销毁方法");
}
}
补充:使用 AbstractApplicationContext 类的 registerShutdownHook() 方法,来确保正常关机并调用相关的 destroy() 方法
public class MainApp {
public static void main(String[] args) {
AbstractApplicationContext context=new ClassPathXmlApplicationContext("Beans.xml");
context.registerShutdownHook();
}
}
四、默认的初始化和销毁方法
多个Bean需要使用相同的初始化和夕会方法,可以在xml的Beans节点使用default-init-method和default-destroy-method属性:
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd" default-destroy-method="destroyMethod" default-init-method="init">
<bean id="helloWorld" class="com.jsonliu.bean.HelloWorld" scope="prototype">
</bean>
<bean id="test" class="com.jsonliu.bean.Test" ></bean>
</beans>