spring中bean的生命周期和后处理器
一、综述
本文使用的spring版本是 5.2.12
spring中bean的生命周期从总体上看有以下这几个阶段
实例化,
属性填充(依赖注入)
Aware接口执行
初始化
销毁
然后spring提供了许多bean后处理器,通过这些后处理器可以在以上这些阶段的执行前后进行干预。
二、bean后处理器
spring中的bean后处理器其实就是sring提前定义好的一些接口,使用的时候提供对应的实现,spring就会帮我们执行。
2.1 bean后处理器接口的介绍
2.1.1 BeanPostProcessor (干预初始化前和初始化后)
首先这是一个接口,其中定义了两个方法,分别会在初始化前,初始化后这两个时机执行,对bean的生命周期进行扩展,这两个方法中已经可以拿到半成品bean对象,并且属性填充已经结束了,可以用来对bean中的一些属性进行校验或者重新赋值。
public interface BeanPostProcessor {
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
要注意的是这个接口是bean后处理器的顶层接口,其他的后处理器都是它的直接或间接子接口。
2.1.2 InstantiationAwareBeanPostProcessor (实例化前后,属性填充)
这个接口是上边BeanPostProcessor接口的子接口,除了父接口提供的方法外,还多提供了几个方法用来干预
实例化前,实例化后,属性填充,还有一个已经废弃的方法。
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
//这个方法如果返回false,生命周期后边的属性填充等就会被跳过
return true;
}
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
// 这个方法可以用来对bean进行属性填充
return null;
}
@Deprecated
@Nullable
default PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return pvs;
}
}
2.1.3DestructionAwareBeanPostProcessor (销毁前)
这个接口也是BeanPostProcessor接口的子接口,其中提供了的方法postProcessBeforeDestruction,
会在bean销毁前执行。
public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
// 销毁前执行
void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
// 针对当前的bean return true上边的销毁前方法会被使用,返回false就不会执行
default boolean requiresDestruction(Object bean) {
return true;
}
}
2.2 bean后处理器的使用
上边介绍了bean后处理器接口,下面来介绍下bean后处理器如何使用。
对于ApplicationContext类型的spring容器,后处理器的使用很简单,创建后处理器接口的实现类,然后注册到spring容器中,然后再执行容器的refresh方法,spring就会帮我们执行后处理器的各种方法。
下面来做一个简单的演示。
2.2.1 定义bean后处理器
这里创建一个后处理器,同时实现DestructionAwareBeanPostProcessor和InstantiationAwareBeanPostProcessor接口,就可以同时演示上边提到的全部方法
要注意的是,bean后处理器在每个bean的生命周期中都会被执行到,所以需要针对被干预的bean做一些条件判断,像下边就判断了bean1的名称
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if("bean1".equals(beanName)){
System.out.println("实例化前方法执行");
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if("bean1".equals(beanName)){
System.out.println("实例化后方法执行");
}
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if("bean1".equals(beanName)){
System.out.println("属性填充方法执行");
}
return null;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if("bean1".equals(beanName)){
System.out.println("初始化前方法执行");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if("bean1".equals(beanName)){
System.out.println("初始化后方法执行");
}
return bean;
}
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if("bean1".equals(beanName)){
System.out.println("销毁前方法执行");
}
}
}
2.2.2bean后处理器的使用
首先先创建一个简单的bean
public class Bean1 {
public Bean1() {
System.out.println("---实例化 bean1---");
}
}
为了演示方便,我们使用一个纯净的ApplicationContext容器的实现类GenericApplicationContext
这个实现类中没有添加spring自带的一些后处理器,方便我们观察结果。
public class LifecycleTest {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean1",Bean1.class);
//注册自定义的bean后处理器
context.registerBean(MyBeanPostProcessor.class);
context.refresh();
//关闭容器,调用销毁方法
context.close();
}
}
运行上边的代码,控制台会输出如下结果
实例化前方法执行
---实例化 bean1---
实例化后方法执行
属性填充方法执行
初始化前方法执行
初始化后方法执行
销毁前方法执行
符合上边的预期顺序,spring就是通过这样的方式来对bean的创建过程进行干预。
如果在MyBeanPostProcessor的最后增加一个方法requiresDestruction,返回false
@Override
public boolean requiresDestruction(Object bean) {
return false;
}
销毁前方法就不会被执行了。
2.3 spring中常见的bean后处理器介绍
上边介绍了bean后处理器接口和如何使用后处理器,接下来看下spring中提供的一些常见的后处理。
2.3.1 AutowiredAnnotationBeanPostProcessor
这个后处理器用来解析@Autowired注解和@Value注解
public class Bean2 {
@Autowired
private Bean1 bean1;
public Bean1 getBean1() {
return bean1;
}
}
先不添加任务后处理器,
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean1",Bean1.class);
context.registerBean("bean2",Bean2.class);
context.refresh();
System.out.println(context.getBean(Bean2.class).getBean1());
}
最终的输出结果中bean2中的属性bean1是null,需要添加后处理器来对 @Autowired注解进行解析。
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean1",Bean1.class);
context.registerBean("bean2",Bean2.class);
// 添加后处理器 AutowiredAnnotationBeanPostProcessor
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
context.refresh();
System.out.println(context.getBean(Bean2.class).getBean1());
}
这样bean2中的属性bean1就有值了。
这个后处理是在postProcessProperties(属性填充)方法中对此注解进行解析的。
2.3.2 CommonAnnotationBeanPostProcessor
这个后处理器用来解析@PostConstruct @PreDestroy @Resource注解
这三个注解在CommonAnnotationBeanPostProcessor的不同方法中被解析
其中 @PostConstruct 注解在初始化前方法中被解析,也就是 postProcessBeforeInitialization
方法
@PreDestroy 注解在销毁前方法中被解析,也就是postProcessBeforeDestruction
方法
@Resource注解 在属性填充方法中被解析,也就是 postProcessProperties
方法中
三、Aware接口
spring提供了几个Aware接口,BeanNameAware,BeanClassLoaderAware,BeanFactoryAware
如果一个bean实现了这几个接口,就会在初始化前方法执行之前先执行这几个aware接口中的方法
3.1 BeanNameAware
public interface BeanNameAware extends Aware {
// name:当前正在创建的bean在beanfactory中的名称
void setBeanName(String name);
}
如果一个bean实现了这个接口,在执行初始化前方法之前就会先执行bean中的setBeanName方法
public class Bean4 implements BeanNameAware {
@Override
public void setBeanName(String name) {
System.out.println("当前bean的名称是:"+name);
}
}
public class LifecycleTest {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean4",Bean4.class);
context.refresh();
}
}
所以这个接口用来在bean内部拿到bean名称。
3.2 BeanClassLoaderAware
这个接口用来在bean内部拿到类加载器
3.3 BeanFactoryAware
这个接口用来在bean内部拿到容器对象 BeanFactory,接口内部也是只有一个setBeanFactory
方法,可以通过这个方法把beanFactory设置给bean的属性。
以上这几个aware接口都会在初始化前方法执行之前执行。
四、bean初始化接口 InitializingBean
这个接口中提供了一个afterPropertiesSet
方法,如何某个Bean实现了这个接口
这个方法会在初始化阶段被执行。
public class Bean3 implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化阶段执行此方法");
}
}