Bean生命周期
1.bean自身的生命周期
- 构造方法
- 依赖注入
- 初始化
- 销毁
代码实例如下(注意这只是模拟,实际上已经被增强bean后处理解析过):
@Component
@Slf4j
public class LifeCycleBean {
//Bean自身的构造方法
public LifeCycleBean(){
log.info("构造方法");
}
//Bean依赖注入
//使用Value注解,此时注入的不是Bean,而是配置参数或者是环境变量中的值
@Autowired
public void autowired(@Value("${JAVA_HOME}") String name){
log.info("依赖注入,环境变量名{}",name);
}
//初始化
@PostConstruct
public void init(){
log.info("初始化");
}
//销毁
@PreDestroy
public void destroy(){
log.info("销毁");
}
}
注意需要再启动类中使用close方法销毁bean,才能看到销毁周期
代码如下:
@SpringBootApplication
public class BeanLifeCycleApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(BeanLifeCycleApplication.class, args);
context.close();
}
}
2.Bean生命周期加强
使用bean后处理器可以对bean的生命周期中进行增强操作
需要实现PostProcessor的子接口
以实例化和销毁接口为例,需要实现InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor接口中的方法
@Slf4j
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
@Override
// 实例化前(即调用构造方法前)执行的方法
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<<<<<<< 实例化前执行,如@PreDestroy");
// 返回null保持原有对象不变,返回不为null,会替换掉原有对象
return null;
}
@Override
// 实例化后执行的方法
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")) {
log.debug("<<<<<<<<<<< 实例化后执行,这里如果返回 false 会跳过依赖注入阶段");
// return false;
}
return true;
}
@Override
// 依赖注入阶段执行的方法
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<<<<<<< 依赖注入阶段执行,如@Autowired、@Value、@Resource");
return pvs;
}
@Override
// 销毁前执行的方法
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBean"))
log.debug("<<<<<<<<<<<销毁之前执行");
}
@Override
// 初始化之前执行的方法
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBean"))
log.debug("<<<<<<<<<<< 初始化之前执行,这里返回的对象会替换掉原本的bean,如 @PostConstruct、@ConfigurationProperties");
return bean;
}
@Override
// 初始化之后执行的方法
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBean"))
log.debug("<<<<<<<<<<< 初始化之后执行,这里返回的对象会替换掉原本的bean,如 代理增强");
return bean;
}
}
注意:这里的方法优先级会比注解的优先级要高,因为就是这些增强方法实现解析注解
3.模板设计方法
在Spring 中 Bean的生命周期添加Bean后处理器的过程用到了模板设计方法:
模板方法设计模式是一种行为设计模式,它定义了一个算法的骨架,将一些步骤交给子类实现。
**核心思想:**定义一个算法的骨架,而将一些步骤延迟到子类中实现。这样可以在不改变算法结构的情况下,通过不同的子类来实现算法的不同行为。
**实现:**通常由一个抽象类来实现,该抽象类中包含了算法的骨架,以及一些步骤的具体实现。这些具体实现可以在抽象类中定义为抽象方法,以便在子类中实现。在模板方法模式中,算法的骨架由抽象类控制,而具体实现则由子类提供。
**优点:**可以在不改变算法结构的情况下,通过不同的子类来实现算法的不同行为。这样可以提高代码的复用性,同时也可以减少代码的重复编写。
在本例中就是不改变Bean其他生命周期实现,只在依赖注入的过程中添加Bean后处理程序,模拟进行@Autowired和@Resource等注解的解析
public class TestMethodTemplatePattern {
public static void main(String[] args) {
MyBeanFactory beanFactory = new MyBeanFactory();
/* beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
@Override
public void inject(Object bean) {
System.out.println("解析 @Autowired");
}
});*/
//后置处理器实现Bean生命周期功能增强
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Autowired"));
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Resource"));
beanFactory.getBean();
}
static class MyBeanFactory {
public Object getBean() {
Object bean = new Object();
System.out.println("构造" + bean);
System.out.println("依赖注入" + bean);
//使用Bean后处理器进行增强
for (BeanPostProcessor processor : processors) {
processor.inject(bean);
}
System.out.println("初始化" + bean);
return bean;
}
private List<BeanPostProcessor> processors = new ArrayList<>();
//在程序执行过程中会添加bean后置处理器
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor){
processors.add(beanPostProcessor);
}
}
//bean后处理器是接口只有一个抽象函数(public abstract可省略)
//函数式接口
interface BeanPostProcessor {
void inject(Object bean);
}
}
函数式接口的要求如下:
- 接口只有一个抽象方法
- 可以有默认方法和静态方法,但不会影响接口的函数式特性
- 可以有Object类的公共方法(如equals、hashCode等),但不会影响接口的函数式特性
- 注解@FunctionalInterface可以用于强制检查接口是否符合函数式接口的要求
- 函数式接口可以用lambda表达式、方法引用等方式实现,从而实现函数式编程的特性。