一文带你深入理解SpringBean生命周期之PostConstruct、PreDestroy详解

简介: 一文带你深入理解SpringBean生命周期之PostConstruct、PreDestroy详解

概述


想必大家在项目中都用过@PostConstruct这个注解把,知道它会在应用启动的时候执行被这个注解标注的方法。其实它还有另外一个注解@PreDestroy,实在Bean销毁前执行,它们都是Bean生命周期的一环,那他们具体在什么阶段执行呢?我们从源码的角度带大家分析下。


注解介绍


@PostConstruct@PreDestroyJSR-250规范中定义的类两个类,表示Bean初始化后和销毁前指定的注解,位于javax.annotation包下,而不是spring jar中的类。

JSR-250, Java Specification Requests的缩写,意思是Java 规范提案。它是Java界共同制定的一个重要标准。它定义了一组通用的注解,比如@PostContruct, @Resource等,防止不同的J2EE组件比如Spring、JBoss、WebSphere等都各自实现一套注解。

Spring作为一个NB的框架,它也遵循上面的规范,实现了对JSR注解的支持。


@PostConstruct


@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}
  • 该注解只能作用于方法上,执行依赖注入后执行任何初始化操作。必须在类投入服务之前调用此方法。
  • 应用PostConstruct的方法可以是公共的、受保护的、包私有的或私有的,但不能是静态的。
  • 被注解方法不能有任何参数。


@PreDestroy


@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PreDestroy {
}
  • 作用于方法上,在容器销毁Bean的时候回调执行。
  • 被注解方法不能有任何参数。
  • 应用PreDestroy的方法可以是公共的、受保护的、包私有的或私有的,但不能是静态的。


实战案例


  1. 定义bean
@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配置了initMethoddestroyMethod属性,以及添加了@PostConstruct@PreDestroy注解。

  1. 查看执行结果

1671110679093.jpg

代码地址:github.com/alvinlkk/sp…

  1. 小结

根据执行结果得知bean初始化和销毁的顺序:

  1. @PostContruct注解对应的方法
  2. 实现了InitializingBean接口的afterPropertiesSet方法
  3. Beaninit-method属性对应的方法
  4. @PreDestroy注解对应的方法
  5. Beandestroy-method属性对应的方法


源码解析


1671110689426.jpg

通过debug快速追踪到实在Bean的初始化阶段。

  1. AbstractAutowireCapableBeanFactoryinitializeBean()方法是bean的初始化入口。
  2. InitDestroyAnnotationBeanPostProcessorBean处理器中调用invokeInitMethods执行@PostContruct对应的方法。


执行过程


1671110700719.jpg

1671110706696.jpg

在Bean的初始化过程前,会回调BeanPostProcessorpostProcessBeforeInitialization方法,这是Spring的一个扩展点,而我们的@PostConstruct就是通过这种扩展机制实现的,它对应的类是InitDestroyAnnotationBeanPostProcessor

InitDestroyAnnotationBeanPostProcessor,顾名思义,它是用来处理初始化和销毁注解的一个Bean处理器,我们看下它的postProcessBeforeInitialization方法。

1671110723113.jpg

这个方法关键是上面的两步,第一步找出所有注解的方法,第二步执行对应的方法,第二步比较简单,就是调用了反射操作,我们重点关注在第一步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的时候设置。

1671110742715.jpg

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


那么CommonAnnotationBeanPostProcessor这个Bean处理器是在什么时候装载到容器中呢?只有它装载到容器中后,才会执行对应的方法。

1671110760998.jpg

  1. 在创建容器的时候,会创建所有的BeanPostProcessors Bean。
  2. 在创建CommonAnnotationBeanPostProcessor这个Bean的时候,就会调用对应的构造方法,设置对应的PostConstruct注解。

大家可以看下这篇文章了解BeanPostProcessor的详细过程SpringBoot扩展点——一文掌握BeanPostProcessor家族

那又是什么时候把CommonAnnotationBeanPostProcessor这个Bean的BeanDefinition加到BeanDefinition工厂中的呢?

只有BeanDefinition工厂中又对应的BeanDefinition才会创建出Bean。答案就是在AnnotationConfigUtils#registerAnnotationConfigProcessors方法中。

1671110769976.jpg


总结


1671110783577.jpg

上面时Bean初始化完整的过程,其实Bean初始化可以自定义的扩展点很多,大家可以根据实际需要扩展。

目录
打赏
0
0
0
0
16
分享
相关文章
Spring系列(三)之Bean的生命周期以及Bean的单例与多例模式
Spring系列(三)之Bean的生命周期以及Bean的单例与多例模式
|
10月前
|
Spring框架中的单例Bean是线程安全的吗?
Spring框架中的单例Bean是线程安全的吗?
115 1
|
8月前
|
@PostConstruct注解的使用
@PostConstruct注解的使用
155 0
一文带你深入理解SpringBean生命周期之InitializingBean详解
一文带你深入理解SpringBean生命周期之InitializingBean详解
772 0
一文带你深入理解SpringBean生命周期之InitializingBean详解
获取类中所有的bean
获取类中所有的bean
64 0
Spring框架中的单例bean是线程安全的吗?
Spring框架中的单例bean是线程安全的吗?
145 0
七.Spring源码剖析-Bean的实例化-属性注入
喜欢我的文章的话就给个好评吧,你的肯定是我坚持写作最大的动力,来吧兄弟们,给我一点动力 这一章节我们来讨论创建Bean过程中的属性注入,在Spring的IOC容器启动过程中,会把定义的Bean封装成BeanDefinition注册到一个ConcurrentHashMap中,Bean注册完成后,就会对单利的且lazy-init=false 的Bean进行实例化。创建Bean的代码在 AbstractAutowireCapableBeanFactory#doCreateBean 中,当Bean创建成功之后,会调用AbstractAutowireCapableBeanFactory#populat
2. 你能说说Spring框架中Bean的生命周期吗?
2. 你能说说Spring框架中Bean的生命周期吗?
133 0
2. 你能说说Spring框架中Bean的生命周期吗?