在《spring中BeanPostProcessor之二:CommonAnnotationBeanPostProcessor(01)》一文中,分析到在调用CommonAnnotationBeanPostProcessor类的postProcessMeredBeanDefinition方法时会先调用其父类的postProcessMeredBeanDefinition方法,下面就来分析CommonAnnotationBeanPostProcessor类的父类InitDestroyAnnoatationBeanPostProcessor。

一、概述

我们先看下CommonAnnotationAnnotationBeanPostProcessor类,上篇中介绍到该类有一个静态代码块会在类初始化的时候调用,在该类中还有一个默认的构造函数,

public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
//@PostConstruct注解,作用在方法上
setInitAnnotationType(PostConstruct.class);
//@PreDestroy注解,作用在方法上
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
}

该构造函数中分别调用了setInitAnnotationType和setDestroyAnnotationType方法,两个方法分别调用其父类的方法,

/**
* Specify the init annotation to check for, indicating initialization
* methods to call after configuration of a bean.
* <p>Any custom annotation can be used, since there are no required
* annotation attributes. There is no default, although a typical choice
* is the JSR-250 {@link javax.annotation.PostConstruct} annotation.
*/
public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
this.initAnnotationType = initAnnotationType;
} /**
* Specify the destroy annotation to check for, indicating destruction
* methods to call when the context is shutting down.
* <p>Any custom annotation can be used, since there are no required
* annotation attributes. There is no default, although a typical choice
* is the JSR-250 {@link javax.annotation.PreDestroy} annotation.
*/
public void setDestroyAnnotationType(Class<? extends Annotation> destroyAnnotationType) {
this.destroyAnnotationType = destroyAnnotationType;
}

分别给的InitDestroyAnnotationBeanPostProcessor的initAnnotationType和destroyAnnotationType赋值@PostConstruct和@PreDestroy注解。

二、详述

上面提到在调用CommonAnnotationBeanPostProcessor类的postProcessMeredBeanDefinition方法时会先调用父类的方法,下面看CommonAnnotationBeanPostProcessor的方法,

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}

上面是CommonAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法,可以看到调用了父类的postProcessMergedBeanDefinition方法,其他的方法在上篇博客中已经分析,来重点分析InitDestroyAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法,

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
LifecycleMetadata metadata = findLifecycleMetadata(beanType);
metadata.checkConfigMembers(beanDefinition);
}

在方法中调用了findLifecycleMetadata和checkConfigMembers方法,

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.
//从lifecycleMetadataCache中取,如果存在则直接返回,不存在则生成一个LifecycleMetadata对象并返回
LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
synchronized (this.lifecycleMetadataCache) {
metadata = this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
metadata = buildLifecycleMetadata(clazz);
this.lifecycleMetadataCache.put(clazz, metadata);
}
return metadata;
}
}
return metadata;
}

在findLifecycleMetadata方法中主要调用的是buildLifecycleMetadata方法,改方法的返回值是LifecycleMetadata对象,之后把该对象放到lifecycleMetadataCache中,那么这里lifecycleMetadata应该是Map类型的,

@Nullable
private final transient Map<Class<?>, LifecycleMetadata> lifecycleMetadataCache = new ConcurrentHashMap<>(256);

buildLifecycleMetadataf方法如下,

private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
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<>(); //判断方法上是否存在initAnnotationType的注解,这里指的就是@PostConstruct注解
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
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);
}
}
//判断方法上是否存在destroyAnnotationType的注解,这里指的就是@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));
}

从上面的分析,可以知道InitDestroyAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法完成的功能就是把类中含有@PostConstrunct和@PreDestroy注解的方法信息缓存到lifecycleMetadataCache中。也就是说在一个被spring管理的类中允许定义被这两个注解修饰的方法,那方法有那些要求那,看上面的new LifecycleElement这里,看LifecycleElement类

public LifecycleElement(Method method) {
if (method.getParameterCount() != 0) {
throw new IllegalStateException("Lifecycle method annotation requires a no-arg method: " + method);
}
this.method = method;
this.identifier = (Modifier.isPrivate(method.getModifiers()) ?
ClassUtils.getQualifiedMethodName(method) : method.getName());
}

看上面的异常,意思是不允许此类方法有方法参数,如果有参数则会抛异常。

三、使用场景

上面分析了InitDestroyAnnotationBeanPostProcessor类中postProcessMergedBeanDefinition方法的作用,就是把类中有@PostConstruct、@PreDestroy两个注解的方法信息进行缓存,至于这两个注解的作用及被这两个注解标记的方法何时调用后面会继续分析。

原创不易,有不正之处欢迎指正。

spring中BeanPostProcessor之三:InitDestroyAnnotationBeanPostProcessor(01)的更多相关文章

  1. spring中BeanPostProcessor之四:AutowiredAnnotationBeanPostProcessor(01)

    在<spring中BeanPostProcessor之二:CommonAnnotationBeanPostProcessor(01)>中分析了CommonAnnotationBeanPos ...

  2. spring中BeanPostProcessor之一:InstantiationAwareBeanPostProcessor(01)

    在spring中beanPostProcessor绝对是开天辟地的产物,给了程序员很多自主权,beanPostProcessor即常说的bean后置处理器. 一.概览 先来说下Instantiatio ...

  3. Spring中BeanPostProcessor

    Spring中BeanPostProcessor 前言: 本文旨在介绍Spring动态配置数据源的方式,即对一个DataSource的配置诸如jdbcUrl,user,password,driverC ...

  4. spring中BeanPostProcessor之二:CommonAnnotationBeanPostProcessor(01)

    在上篇博客中分享了InstantiationAwareBeanPostProcessor接口中的四个方法,分别对其进行了详细的介绍,在文末留下了一个问题,那就是postProcessPropertie ...

  5. spring(三):spring中BeanPostProcessor的使用

    spring中实现BeanPostProcessor的后置处理器 ApplicationContextAwareProcessor 进入该实现类内部 可以看到:该类帮我们组建IOC容器,判断我们的be ...

  6. spring中BeanPostProcessor之一:InstantiationAwareBeanPostProcessor(03)

    前面介绍了InstantiationAwareBeanPostProcessor后置处理器的postProcessBeforeInstantiation和postProcessAfterInstant ...

  7. spring中BeanPostProcessor之一:InstantiationAwareBeanPostProcessor(02)

    在上篇博客中写道了bean后置处理器InstantiationAwareBeanPostProcessor,只介绍了其中一个方法的作用及用法,现在来看postProcessBeforeInstanti ...

  8. Spring中的BeanPostProcessor

    一.何谓BeanProcessor BeanPostProcessor是SpringFramework里非常重要的核心接口之一,我先贴出一段源代码: /* * Copyright 2002-2015 ...

  9. Spring中的BeanPostProcessor详解

    Spring中的BeanPostProcessor详解 概述 BeanPostProcessor也称为Bean后置处理器,它是Spring中定义的接口,在Spring容器的创建过程中(具体为Bean初 ...

随机推荐

  1. [Docker01] The Docker Road

    The Docker Road Docker是什么? Docker是docker容器为资源分隔和调度的基本单位,封装整个软件运行时环境,为开发者和系统管理员设计的,用于构建,发布和运行分布式应用的平台 ...

  2. 最便捷的神经网络可视化工具之一--Flashtorch

    前言 几周前,我在AnitaB.org组织的Hopperx1 London上发表了演讲作为伦敦科技周的一部分. 在演讲结束后,我收到了热烈的反馈,所以我决定写一个稍微长一点的演讲版本来介绍FlashT ...

  3. 第 k 小的数

    一.寻找两个有序数组的中位数 1.1 问题描述 给定两个大小为 m 和 n 的不同时为空的有序数组 nums1 和 nums2.找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m ...

  4. Windows程序卡顿、无响应问题定位

    当windows程序出现异常.界面卡顿.无响应情况时,在有工程和源码的情况下,程序员通常是打开IDE,在DEBUG模式下进行调试.但如果是一个RELEASE程序,且无调试环境,该如何来定位呢. 这里介 ...

  5. 使用vue-cli脚手架创建vue项目

    使用vue-cli脚手架创建vue项目 首先,你已经安装了node. 使用vue-cli@2 创建项目 执行 命令: npm i -g vue-cli@2 //全局安装vue-cli@2脚手架 : v ...

  6. win10下vue-devtools的安装和使用

    网上关于vue-devtools的安装数不胜数,但是自己操作起来却总是遇到问题. 写下这篇随笔,以防以后忘记. vue-devtools是一款基于chrome游览器的插件,用于调试vue应用,这可以极 ...

  7. php 安装教程

    php 安装教程 本文采用php7.0.1作为样例,进行安装. 系统环境: CentOS6.7. gcc 4.8.2 libzip 1.0.1 在安装之前,可以先更新CentOS系统. yum -y ...

  8. async和await是如何实现异步编程?

    目录 异步编程样例 样例解析 浅谈Promise如何实现异步执行 参考 1.异步编程样例 样例: // 等待执行函数 function sleep(timeout) { return new Prom ...

  9. CCF2018 12 2题,小明终于到家了

    最近在愁着备考,拿CCF刷题,就遇到这个难题,最后搜索了一下大佬们的方法,终于解决, 问题描述 一次放学的时候,小明已经规划好了自己回家的路线,并且能够预测经过各个路段的时间.同时,小明通过学校里安装 ...

  10. vue 刮刮乐功能实现

    <template> <!--游玩区域--> <div class="panel"> <canvas id="canvas&qu ...