第三讲-Bean的生命周期和模板方法
第三讲 Bean的生命周期和模板方法
1. Spring 生命周期的各个阶段
首先准备好一个Spring容器:
@SpringBootApplication
public class A03Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(A03Application.class, args);
context.close();
}
}
准备一个Bean:
package com.cherry.chapter1.a03;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class LifeCycleBean {
private static final Logger log = LoggerFactory.getLogger(LifeCycleBean.class);
public LifeCycleBean(){
log.debug("构造方法被调用");
}
@Autowired
public void autowired(@Value("${JAVA_HOME}")String javaHome){
log.debug("依赖注入:{}",javaHome);
}
@PostConstruct
public void init(){
log.debug("初始化");
}
@PreDestroy
public void destroy(){
log.debug("销毁");
}
}
接下来我们启动程序,查看运行结果:
2024-07-21 11:11:50.641 DEBUG 17064 --- [ main] com.cherry.chapter1.a03.LifeCycleBean : 构造方法被调用
2024-07-21 11:11:50.644 DEBUG 17064 --- [ main] com.cherry.chapter1.a03.LifeCycleBean : 依赖注入:D:\development_tools\jdk17\jdk-17.0.10
2024-07-21 11:11:50.646 DEBUG 17064 --- [ main] com.cherry.chapter1.a03.LifeCycleBean : 初始化
2024-07-21 11:11:50.941 WARN 17064 --- [ main] o.s.b.a.f.FreeMarkerAutoConfiguration : Cannot find template location(s): [classpath:/templates/] (please add some templates, check your FreeMarker configuration, or set spring.freemarker.checkTemplateLocation=false)
2024-07-21 11:11:50.976 INFO 17064 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2024-07-21 11:11:50.984 INFO 17064 --- [ main] com.cherry.chapter1.a03.A03Application : Started A03Application in 1.642 seconds (JVM running for 2.613)
2024-07-21 11:11:51.248 DEBUG 17064 --- [ main] com.cherry.chapter1.a03.LifeCycleBean : 销毁
我们可以看到,执行的流程如下:
- 首先执行Bean的构造方法
- 其次执行Bean的依赖注入方法
- 紧接着执行Bean的初始化方法
- 最后执行Bean的销毁方法
前面我们讲过,Bean后处理器是对Bean生命周期各个阶段的一些扩展,那都有哪些扩展呢?这里举一些例子:
package com.cherry.chapter1.a03;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
private static final Logger log = LoggerFactory.getLogger(MyBeanPostProcessor.class);
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")){
log.debug("<<<< 实例化之前执行,构造方法之前执行");
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")){
log.debug("<<<< 实例化之后执行,构造方法执行完毕之后执行");
}
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")){
log.debug("<<<< 依赖注入阶段执行.如@Autowird,@Value,@Resource");
}
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")){
log.debug("<<<< 初始化之前执行,这里返回的对象会替换掉原本的bean, 如@PostConstruct, 2ConfigurationProperties");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")){
log.debug("<<<< 依赖注入阶段执行,这里返回的对象会替换掉原本的bean,如代理增强");
}
return bean;
}
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")){
log.debug("<<<< 销毁前执行,如@PreDestory");
}
}
}
执行结果如下:
2024-07-21 11:43:30.492 DEBUG 6504 --- [ main] c.c.chapter1.a03.MyBeanPostProcessor : <<<< 实例化之前执行,构造方法之前执行
2024-07-21 11:43:30.493 DEBUG 6504 --- [ main] com.cherry.chapter1.a03.LifeCycleBean : 构造方法被调用
2024-07-21 11:43:30.496 DEBUG 6504 --- [ main] c.c.chapter1.a03.MyBeanPostProcessor : <<<< 实例化之后执行,构造方法执行完毕之后执行
2024-07-21 11:43:30.496 DEBUG 6504 --- [ main] c.c.chapter1.a03.MyBeanPostProcessor : <<<< 依赖注入阶段执行.如@Autowird,@Value,@Resource
2024-07-21 11:43:30.497 DEBUG 6504 --- [ main] com.cherry.chapter1.a03.LifeCycleBean : 依赖注入:D:\development_tools\jdk17\jdk-17.0.10
2024-07-21 11:43:30.498 DEBUG 6504 --- [ main] c.c.chapter1.a03.MyBeanPostProcessor : <<<< 初始化之前执行,这里返回的对象会替换掉原本的bean, 如@PostConstruct, 2ConfigurationProperties
2024-07-21 11:43:30.498 DEBUG 6504 --- [ main] com.cherry.chapter1.a03.LifeCycleBean : 初始化
2024-07-21 11:43:30.498 DEBUG 6504 --- [ main] c.c.chapter1.a03.MyBeanPostProcessor : <<<< 依赖注入阶段执行,这里返回的对象会替换掉原本的bean,如代理增强
2024-07-21 11:43:30.840 WARN 6504 --- [ main] o.s.b.a.f.FreeMarkerAutoConfiguration : Cannot find template location(s): [classpath:/templates/] (please add some templates, check your FreeMarker configuration, or set spring.freemarker.checkTemplateLocation=false)
2024-07-21 11:43:30.884 INFO 6504 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2024-07-21 11:43:30.892 INFO 6504 --- [ main] com.cherry.chapter1.a03.A03Application : Started A03Application in 1.932 seconds (JVM running for 3.291)
2024-07-21 11:43:31.166 DEBUG 6504 --- [ main] c.c.chapter1.a03.MyBeanPostProcessor : <<<< 销毁前执行,如@PreDestory
2024-07-21 11:43:31.167 DEBUG 6504 --- [ main] com.cherry.chapter1.a03.LifeCycleBean : 销毁
2. 模板设计模式 Template Method Pattern
举个例子,如果我们想自己设计一个 BeanFactory:
package com.cherry.a03;
public class TestMethodTemplate {
public static void main(String[] args) {
MyBeanFactory beanFactory = new MyBeanFactory();
beanFactory.getBean();
}
static class MyBeanFactory {
public Object getBean() {
Object bean = new Object();
System.out.println("构造 " + bean);
System.out.println("依赖注入 " + bean);
System.out.println("初始化 " + bean);
return bean;
}
}
}
运行结果如下:
构造 java.lang.Object@17a7cec2
依赖注入 java.lang.Object@17a7cec2
初始化 java.lang.Object@17a7cec2
进程已结束,退出代码为 0
后来呢,我们希望对于我们自己设计的 BeanFactory 进行一个功能扩展,例如加入对 @Autowired 注解解析的支持,如果要加入这个功能,肯定是要对现有的代码进行改写。这样的代码其实扩展性并不好,因为在新建新功能的时候要改动原有代码。那怎样设计代码才能让我们代码的灵活性和扩展性更好呢?
我们的做法是先设计一个接口,我们希望将一些变化的东西抽象成一个借口:
static interface BeanPostProcessor {
public void inject(); // 对依赖注入阶段进行功能扩展
}
紧接着我们创建存储 BeanPostProcessor 对象的一个集合,用于添加我们创建的后处理器。
private List<BeanPostProcessor> processors = new ArrayList<>();
public void addBeanPostProcessor(BeanPostProcessor processor) {
processors.add(processor);
}
紧接着,在我们认为想要实现这个功能的地方通过遍历集合的方式使用我们添加好的 BeanPostProcessor 对象集合:
for (BeanPostProcessor processor: processors) {
processor.inject(bean);
}
最后在我们创建 BeanFactory 的时候添加一个自定义的 BeanPostProcessor ,并实现方法:
MyBeanFactory beanFactory = new MyBeanFactory();
beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
@Override
public void inject(Object bean) {
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Autowired"));
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Resource"));
}
});
完整的代码如下:
package com.cherry.chapter1.a03;
import java.util.ArrayList;
import java.util.List;
public class TesttemplateMethod {
public static void main(String[] args) {
MyBeanFactory beanFactory = new MyBeanFactory();
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Autowired"));
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Resource"));
beanFactory.getBean();
}
// 模板方法 Template Method Pattern
static class MyBeanFactory{
public Object getBean(){
Object bean = new Object();
System.out.println("构造 "+bean);
System.out.println("依赖注入 "+bean);
for (BeanPostProcessor bp:processors){
bp.inject(bean);
}
System.out.println("初始化 "+bean);
return bean;
}
private List<BeanPostProcessor> processors = new ArrayList<>();
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor){
processors.add(beanPostProcessor);
}
}
static interface BeanPostProcessor {
public void inject(Object bean); // 对依赖注入阶段的扩展
}
}
运行结果如下:
构造 java.lang.Object@4b6995df
依赖注入 java.lang.Object@4b6995df
解析 @Autowired
解析 @Resource
初始化 java.lang.Object@4b6995df
模板方法的核心就是将不能确定的部分抽象为一个接口,将来在特定的时机调用抽象方法,通过回调的方式对接口中的功能进行扩展。这种设计模式我们称之为模板方法,在模板方法里有静态代码,也就是固定的步骤代码;动态代码指的是需要回调的接口。

浙公网安备 33010602011771号