作用

  1.注解@PostConstruct可以添加在类的方法上面,如果这个类被IOC容器托管,那么在对Bean进行初始化前的时候会调用被这个注解修饰的方法

被定义在哪里?

  1.被定义在了CommonAnnotationBeanPostProcessor类,这个类是InitDestroyAnnotationBeanPostProcessor类的子类,也实现了InstantiationAwareBeanPostProcessor接口(BeanDefinition的后置处理接口)。代码展示:

public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
}

  2.故在这个CommonAnnotationBeanPostProcessor类实例化的时候注解就会被定义下来。

    

在何处被扫描?

  1.在BeanDefinition的后置处理时调用 postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName)进行扫描

  2.在初始化前中调用处理器InitDestroyAnnotationBeanPostProcessor的postProcessBeforeInitialization方法进行扫描

  汇总:

    两处扫描的本质都是调用了 LifecycleMetadata findLifecycleMetadata(Class<?> clazz)方法(位于InitDestroyAnnotationBeanPostProcessor类里面),

扫描方法分析

  1.findLifecycleMetadata方法分析:

    说明:

      1)判断缓存有没有构建,没有构建则调用构建Metadata对象的方法

      2)缓存构建了,就去缓存里面寻找,没找到就调用构建Metadata对象的方法,把拿回来的对象存入缓存中

    代码展示:

private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
if (this.lifecycleMetadataCache == null) {
return buildLifecycleMetadata(clazz);
}
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;
}

  2.buildLifecycleMetadata方法分析:

    说明:

      1)主要应用类反射机制的概念,doWithLocalMethods通过类获取所有方法,然后利用反射机制构建调用对象

      2)LifecycleMetadata对象便是包含了该类的所有的初始化方法和销毁方法

    代码展示:

private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
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<>(); //doWithLocalMethods,深入源码其实可知是通过类对象取出所有的方法,逐一进行调用lambda表达式的方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
//判断初始化方法
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element);
}
//判断销毁方法
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
currDestroyMethods.add(new LifecycleElement(method));
}
}); //根据继承关系故会有父类要比子类先构造,子类要比父类先销毁
//所以这里采用头插法
initMethods.addAll(0, currInitMethods);
//这里会往末尾存放
destroyMethods.addAll(currDestroyMethods);
//寻找父类
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class); return new LifecycleMetadata(clazz, initMethods, destroyMethods);
}

在何处被调用?(过程分析)

  1.既然是在初始化前的处理器中调用,而且源于InitDestroyAnnotationBeanPostProcessor这个处理器会在初始化前这个步骤中执行@PostConstruct的方法

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//这一步是寻找
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
//这一步是调用
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
}
return bean;
}

  

  2.基于反射机制调用方法对象来调用类对象的方法:

public void invokeInitMethods(Object target, String beanName) throws Throwable {
Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
Collection<LifecycleElement> initMethodsToIterate = (checkedInitMethods != null ? checkedInitMethods : this.initMethods);
if (!initMethodsToIterate.isEmpty()) {
for (LifecycleElement element : initMethodsToIterate) {
element.invoke(target);
}
}
}

    

postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName)

注解@PostConstruct分析的更多相关文章

  1. 【JPA】注解@PostConstruct、@PreDestroy

    从Java EE5规范开始,Servlet增加了两个影响Servlet生命周期的注解@PostConstruct和@PreConstruct.这两个注解被用来修饰一个非静态的void()方法,而且这个 ...

  2. uboot-的start.S详细注解及分析

    原文地址:uboot-的start.S详细注解及分析 作者:zhouyg11 大多数bootloader都分为stage1和stage2两部分,u-boot也不例外.依赖于CPU体系结构的代码(如设备 ...

  3. Spring注解@PostConstruct与@PreDestroy

    关于在spring  容器初始化 bean 和销毁前所做的操作定义方式有三种: 第一种:通过@PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作 第二 ...

  4. servlet注解@PostConstruct与@PreDestroy

    从Java EE 5规范开始,Servlet中增加了两个影响Servlet生命周期的注解(Annotion):@PostConstruct和@PreDestroy.这两个注解被用来修饰一个非静态的vo ...

  5. 注解@PostConstruct与@PreDestroy讲解及实例

    从Java EE 5规范开始,Servlet中增加了两个影响Servlet生命周期的注解(Annotion):@PostConstruct和@PreDestroy.这两个注解被用来修饰一个非静态的vo ...

  6. 注解@PostConstruct与@PreDestroy 特性说明

    简介 Java EE5 引入了@PostConstruct和@PreDestroy这两个作用于Servlet生命周期的注解,实现Bean初始化之前和销毁之前的自定义操作.此文主要说明@PostCons ...

  7. Spring 注解详细分析解释有实例

    概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作.如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO ...

  8. springboot - Constructor、@Autowired、@PostConstruct分析

    1.Constructor 构造方法 2.@Autowired 依赖注入 3.@PostConstruct 在依赖注入完成后被自动调用 4. 三者的顺序: 从依赖注入的字面意思就可以知道,要将对象p注 ...

  9. 注解@PostConstruct与@PreDestroy详解及实例

    Java EE5 引入了@PostConstruct和@PreDestroy这两个作用于Servlet生命周期的注解,实现Bean初始化之前和销毁之前的自定义操作.此文主要说明@PostConstru ...

随机推荐

  1. PowerDesigner安装

    1.双击安装包进行安装 2.选择PRC 3.一路往下就行 4.将下图文件夹中的内容覆盖安装的内容 ----------------------------------------分割线 5.安装成功 ...

  2. Unsupervised Person Re-identification by Soft Multilabel Learning

    简介: 这是一篇19年CVPR的跨域无监督Re-ID论文,在Market1501和DukeMTMC-reID上分别达到了67.7%和67.1%的rank-1精度,算是一篇将准确度刷得比较高的论文了,在 ...

  3. [ 1 x 1 ] Convolution-1*1卷积的作用

    一.卷积神经网络中的卷积(Convolution in a convoluted neural network) 具体内容亲参考<深度学习>. 二.1*1卷积(one by one con ...

  4. pyinstaller打包一些三方库后,报资源不存在

    在目录site-packages\PyInstaller\hooks下新建对应文件hook-对应三方库名字.py,如hook-ngender.py 编辑hook-ngender.py: from Py ...

  5. Mac Sierra开启读写NTFS

    查看卷标diskutil list sudo vim /etc/fstab,开启WinD盘符读写,添加如下: LABEL=WinD none ntfs rw,auto,nobrowse 磁盘工具重新挂 ...

  6. Java + Selenium + OpenCV解决自动化测试中的滑块验证

    最近工作过程中,一个常用的被测网站突然增加了滑块验证环节,导致整个自动化项目失效了. 为了解决这个滑块验证问题,在网上查阅了一些资料后,总结并实现了解决方案,现记录如下. 1.滑块验证思路 被测对象的 ...

  7. [SWPU2019]Web1-1|SQL注入

    1.打开之后界面如下: 2.查看源代码.登录注入等未发现有用信息,结果如下: 3.进行注册试试,注册时发现admin账户已被注册,随便注册一个账户并登录,结果如下: 申请发布广告页面如下: 4.发布广 ...

  8. 【AcWing】周赛

    A.糖果 题目链接 链接 题目描述 给定三个正整数 a,b,c. 请计算 ⌊a+b+c2⌋,即 a,b,c 相加的和除以 2 再下取整的结果. 输入格式 第一行包含整数 T,表示共有 T 组测试数据. ...

  9. C#异步延迟Task.Delay

    一. 1.Task.Delay实质是创建一个任务,再任务中开启一个定时间,然后延时指定的时间2.Task.Delay不和await一起使用情况,当代码遇到Task.Delay一句时,创建了了一个新的任 ...

  10. std::hash<std::pair<int, int> >

    标题是搞笑的 ! 这个问题只需要 since C++11 问题:怎么让 unordered_map 支持使用 pair 作为 key? 如果你能把两个东西压到一个基本类型里那么就不用解决这个问题了 . ...