想必大家在项目中都用过@PostConstruct这个注解把,知道它会在应用启动的时候执行被这个注解标注的方法。其实它还有另外一个注解@PreDestroy,实在Bean销毁前执行,它们都是Bean生命周期的一环,那他们具体在什么阶段执行呢?我们从源码的角度带大家分析下。
@PostConstruct和@PreDestroy是JSR-250规范中定义的类两个类,表示Bean初始化后和销毁前指定的注解,位于JAVAx.annotation包下,而不是spring jar中的类。
JSR-250, Java Specification Requests的缩写,意思是Java 规范提案。它是Java界共同制定的一个重要标准。它定义了一组通用的注解,比如@PostContruct, @Resource等,防止不同的J2EE组件比如Spring、JBoss、WebSphere等都各自实现一套注解。
Spring作为一个NB的框架,它也遵循上面的规范,实现了对JSR注解的支持。
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PreDestroy {
}
@Slf4j
@ToString
public class LifeCycleBean implements InitializingBean {
private String prop;
public LifeCycleBean() {
log.info("%%%%%%%%%%%%%%%%%%%% LifeCycleBean 实例化");
}
public LifeCycleBean(String prop) {
this.prop = prop;
}
public String getProp() {
return prop;
}
@PostConstruct
private void postContruct() {
log.info("%%%%%%%%%%%%%%%%%%%% LifeCycleBean postContruct");
}
@PreDestroy
private void preDestory() {
log.info("%%%%%%%%%%%%%%%%%%%% LifeCycleBean preDestory");
}
public void setProp(String prop) {
this.prop = prop;
}
public void init() {
log.info("%%%%%%%%%%%%%%%%%%%% LifeCycleBean 初始化");
this.setProp("hello");
}
public void destroy() {
log.info("%%%%%%%%%%%%%%%%%%%% LifeCycleBean destroy");
this.setProp("hello");
}
@Override
public void afterPropertiesSet() throws Exception {
log.info("%%%%%%%%%%%%%%%%%%%% LifeCycleBean afterPropertiesSet");
}
}
@Bean(name = "lifeCycleBean", initMethod = "init", destroyMethod = "destroy")
public LifeCycleBean createLifeCycleBean() {
return new LifeCycleBean();
};
定义了Bean初始化和销毁相关的方法,包括实现了InitializingBean接口,Bean配置了initMethod、destroyMethod属性,以及添加了@PostConstruct、@PreDestroy注解。
代码地址:Github.com/alvinlkk/sp…
根据执行结果得知bean初始化和销毁的顺序:
通过debug快速追踪到实在Bean的初始化阶段。
在Bean的初始化过程前,会回调BeanPostProcessor的
postProcessBeforeInitialization方法,这是Spring的一个扩展点,而我们的@PostConstruct就是通过这种扩展机制实现的,它对应的类是InitDestroyAnnotationBeanPostProcessor。
InitDestroyAnnotationBeanPostProcessor,顾名思义,它是用来处理初始化和销毁注解的一个Bean处理器,我们看下它的postProcessBeforeInitialization方法。
这个方法关键是上面的两步,第一步找出所有注解的方法,第二步执行对应的方法,第二步比较简单,就是调用了反射操作,我们重点关注在第一步findLifecycleMetadata方法。
/**
* 查找指定类型的生命周期元数据.
*/
private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
// lifecycleMetadataCache为空,则重新创建生命周期元数据.
if (this.lifecycleMetadataCache == null) {
// HAppens after deserialization, during destruction...
return buildLifecycleMetadata(clazz);
}
// 采用双重检查锁机制来进行快速检查,尽量减少对锁的使用。
// 首先进行快速检查,只需最少的锁竞争.
// Quick check on the concurrent map first, with minimal locking.
LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
// 加锁处理
synchronized (this.lifecycleMetadataCache) {
metadata = this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
// 关键方法,构建LifecycleMetadata
metadata = buildLifecycleMetadata(clazz);
this.lifecycleMetadataCache.put(clazz, metadata);
}
return metadata;
}
}
return metadata;
}
查看关键的方法buildLifecycleMetadata的源码如下:
/**
* 创建生命周期元数据.
*/
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
// 判断当前Bean是否包含@PostContruct,@PreDestroy,如果不包含,直接返回
if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
return this.emptyLifecycleMetadata;
}
// 初始化相关元数据
List<LifecycleElement> initMethods = new ArrayList<>();
// 销毁相关的元数据
List<LifecycleElement> destroyMethods = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<LifecycleElement> currInitMethods = new ArrayList<>();
final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
// 遍历类中的methods
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
// 判断方法是有@PostConstruct注解
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
// 判断方法是有@PreDestroy注解
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
currDestroyMethods.add(new LifecycleElement(method));
if (logger.isTraceEnabled()) {
logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
});
initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
// 查找父类
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
new LifecycleMetadata(clazz, initMethods, destroyMethods));
}
复制代码
该方法主要是遍历bean对应的class以及父class中包含@PostConstruct、@PreDestroy注解的方法,构建出
LifecycleMetadata对象。
有一个问题,上面查找其实用的都是initAnnotationType、@PostConstruct、@PreDestroy属性,那他们是在上面时候设置为@PostConstruct、@PreDestroy呢?
我们可以看父类
CommonAnnotationBeanPostProcessor的构造方法,它在实例化CommonAnnotationBeanPostProcessor这个bean的时候设置。
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
// 设置PostConstruct
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
// java.naming module present on JDK 9+?
if (jndiPresent) {
this.jndiFactory = new SimpleJndiBeanFactory();
}
}
那么
CommonAnnotationBeanPostProcessor这个Bean处理器是在什么时候装载到容器中呢?只有它装载到容器中后,才会执行对应的方法。
大家可以看下这篇文章了解BeanPostProcessor的详细过程SpringBoot扩展点——一文掌握BeanPostProcessor家族
那又是什么时候把
CommonAnnotationBeanPostProcessor这个Bean的BeanDefinition加到BeanDefinition工厂中的呢?
只有BeanDefinition工厂中又对应的BeanDefinition才会创建出Bean。答案就是在AnnotationConfigUtils#
registerAnnotationConfigProcessors方法中。
上面时Bean初始化完整的过程,其实Bean初始化可以自定义的扩展点很多,大家可以根据实际需要扩展。
作者:JAVA旭阳
链接:
https://juejin.cn/post/7111258070352658446