Bean的生命周期
这一节我们来探究一下bean的生命周期,这也是个面试高频问题。这里我们先搭建一个基于SpringBoot应用程序来分析一下。
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(DemoBoot.class, args);
context.close();
}
@Component
public class DemoBean {
public DemoBean() {System.out.println("DemoBean构造执行!");}
@Autowired
public void autowire(@Value("${JAVA_HOME}") String home) {
System.out.println("依赖注入:" + home);
}
@PostConstruct
public void init(){System.out.println("初始化");}
@PreDestroy
public void destroy(){System.out.println("销毁");}
}
运行结果:
DemoBean构造执行!
依赖注入:D:\Java\jdk1.8
初始化
销毁
这个程序没什么特殊的地方根据运行结果可以看出bean的运行过程。大致的过程基本可以分为:实例化、依赖注入、初始化、销毁四个阶段。但是每个阶段都附加了很多很多的后置处理器,正是在每个阶段的后置处理器实现了很多很多的功能,我们写个例子测试一下。
@Component
public class DemoBeanPostProcessor implements InstantiationAwareBeanPostProcessor,
DestructionAwareBeanPostProcessor {
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if(beanName.equals("demoBean"))
System.out.println("BeanPostProcessor:销毁之前执行方法!");
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if(beanName.equals("demoBean"))
System.out.println("BeanPostProcessor:实例化之前执行方法!");
return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if(beanName.equals("demoBean"))
System.out.println("BeanPostProcessor:实例化之后执行方法!");
return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if(beanName.equals("demoBean"))
System.out.println("BeanPostProcessor:依赖注入执行方法!");
return InstantiationAwareBeanPostProcessor.super.postProcessProperties(pvs, bean, beanName);
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return InstantiationAwareBeanPostProcessor.super.postProcessPropertyValues(pvs, pds, bean, beanName);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("demoBean"))
System.out.println("BeanPostProcessor:初始化之前执行方法!");
return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("demoBean"))
System.out.println("BeanPostProcessor:初始化之后执行方法!");
return InstantiationAwareBeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
定义一个专门处理这些后置处理器的bean,实现InstantiationAwareBeanPostProcessor接口和DestructionAwareBeanPostProcessor接口并实现他们的方法。由代码中的打印注释可以看到每个方法的执行时机。
对比上面没有添加后置处理器的结果,bean在整个生命周期中,因为后置处理器的存在,增添了很多的步骤来填充整个周期过程。
模板方法
上面的后置处理器的代码方式,运用模板方法的设计模式,这里扩展一下该设计模式的设计思想。
public class DemoMethodTemplate {
public static void main(String[] args) {
MyBeanFactory myBeanFactory = new MyBeanFactory();
myBeanFactory.addProcessors(bean -> {
System.out.println("处理bean");
return bean;
});
myBeanFactory.getBean();
}
static class MyBeanFactory{
private List<MyBeanPostProcessor> processors = new ArrayList<>();
public Object getBean(){
Object bean = new Object();
System.out.println("执行构造!");
System.out.println("依赖注入!");
for (MyBeanPostProcessor processor : processors) {
bean = processor.inject(bean);
}
System.out.println("初始化!");
System.out.println("销毁!");
return bean;
}
public void addProcessors(MyBeanPostProcessor processor){
processors.add(processor);
}
}
interface MyBeanPostProcessor{
Object inject(Object bean);
}
}
我们简单模仿一个BeanFactory获取bean的过程,当执行getBean()方法的时候,将会调用bean的构造方法,做一系列的bean生命周期中的操作,这里用简单的打印代替。这时候,我们这些流程就是固定的,我们现在有这样的一个需求,需要给初始化之前添加一些后置处理器来对bean做增强操作,该怎么做呢。我们直接看上面的代码呈现,步骤如下:
- 我们定义一个公共接口MyBeanPostProcessor,后面我们写的处理器需要定义成什么操作都需要实现该接口;
- 在MyBeanFactory中定义一个结合,用来存放所有该接口形式的类集合;
- 在MyBeanFactory中添加一个addProcessors方法,用来给集合中添加后置处理器;
- main方法中调用addProcessors方法,增加一个MyBeanPostProcessor的实现类,并实现要求的方法;
- 在需要增强的步骤中循环集合,并执行。
整体流程走下来,完成了什么呢,我们发现不需要对bean本身做任何修改,当需要做增强操作时,只需要增加一个实现类并实现其中方法做具体操作。当getBean的时候自然会循环调用。这就是模板方法的含义,我们这里将bean本身传入接口定义的方法,这样可以将需要操作的bean传给要实现的方法,方法实现后,可以将增强后的bean再次返回。这也就是上面众多Spring提供的后置处理器里bean参数的意义。如果不做任何操作,默认是将原有bean原样返回。