作用

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

被定义在哪里?

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

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

  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对象的方法,把拿回来的对象存入缓存中

    代码展示:

  1. private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
  2. if (this.lifecycleMetadataCache == null) {
  3. return buildLifecycleMetadata(clazz);
  4. }
  5. LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
  6. if (metadata == null) {
  7. synchronized (this.lifecycleMetadataCache) {
  8. metadata = this.lifecycleMetadataCache.get(clazz);
  9. if (metadata == null) {
  10. metadata = buildLifecycleMetadata(clazz);
  11. this.lifecycleMetadataCache.put(clazz, metadata);
  12. }
  13. return metadata;
  14. }
  15. }
  16. return metadata;
  17. }

  2.buildLifecycleMetadata方法分析:

    说明:

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

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

    代码展示:

  1. private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
  2. List<LifecycleElement> initMethods = new ArrayList<>();
  3. List<LifecycleElement> destroyMethods = new ArrayList<>();
  4. Class<?> targetClass = clazz;
  5.  
  6. do {
  7. final List<LifecycleElement> currInitMethods = new ArrayList<>();
  8. final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
  9.  
  10. //doWithLocalMethods,深入源码其实可知是通过类对象取出所有的方法,逐一进行调用lambda表达式的方法
  11. ReflectionUtils.doWithLocalMethods(targetClass, method -> {
  12. //判断初始化方法
  13. if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
  14. LifecycleElement element = new LifecycleElement(method);
  15. currInitMethods.add(element);
  16. }
  17. //判断销毁方法
  18. if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
  19. currDestroyMethods.add(new LifecycleElement(method));
  20. }
  21. });
  22.  
  23. //根据继承关系故会有父类要比子类先构造,子类要比父类先销毁
  24. //所以这里采用头插法
  25. initMethods.addAll(0, currInitMethods);
  26. //这里会往末尾存放
  27. destroyMethods.addAll(currDestroyMethods);
  28. //寻找父类
  29. targetClass = targetClass.getSuperclass();
  30. }
  31. while (targetClass != null && targetClass != Object.class);
  32.  
  33. return new LifecycleMetadata(clazz, initMethods, destroyMethods);
  34. }

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

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

  1. @Override
  2. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  3. //这一步是寻找
  4. LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
  5. try {
  6. //这一步是调用
  7. metadata.invokeInitMethods(bean, beanName);
  8. }
  9. catch (InvocationTargetException ex) {
  10. throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
  11. }
  12. catch (Throwable ex) {
  13. throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
  14. }
  15. return bean;
  16. }

  

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

  1. public void invokeInitMethods(Object target, String beanName) throws Throwable {
  2. Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
  3. Collection<LifecycleElement> initMethodsToIterate = (checkedInitMethods != null ? checkedInitMethods : this.initMethods);
  4. if (!initMethodsToIterate.isEmpty()) {
  5. for (LifecycleElement element : initMethodsToIterate) {
  6. element.invoke(target);
  7. }
  8. }
  9. }

    

  1. 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. Spring框架系列(11) - Spring AOP实现原理详解之Cglib代理实现

    我们在前文中已经介绍了SpringAOP的切面实现和创建动态代理的过程,那么动态代理是如何工作的呢?本文主要介绍Cglib动态代理的案例和SpringAOP实现的原理.@pdai Spring框架系列 ...

  2. NC15163 逆序数

    NC15163 逆序数 题目 题目描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数.比如一个序列为 \ ...

  3. 当在命令行输入"pip install xxx"

    当输入"pip install xxx"时发生了什么 不知道你在下载一些包的时候有没有什么疑惑,输入了"pip install xxx" ,系统是如何找到对应的 ...

  4. Tapdata 实时数据融合平台解决方案(五):落地

    作者介绍:TJ,唐建法,Tapdata 钛铂数据 CTO,MongoDB中文社区主席,原MongoDB大中华区首席架构师,极客时间MongoDB视频课程讲师. 通过前面几篇文章,我们从企业数据整合与分 ...

  5. Graph-Based Social Relation Reasoning

    title: Graph-Based Social Relation Reasoning, 2020 task: we propose a simpler, faster, and more accu ...

  6. Python语法糖,提升编程幸福感!!!

    转载请注明出处️ 作者:测试蔡坨坨 原文链接:caituotuo.top/a52bc938.html 大家好,我是测试蔡坨坨. 今天,我们来盘点一下Python中的那些语法糖. 什么是语法糖?语法糖不 ...

  7. 云ATM架构设计

    云ATM架构设计 启动程序(Start.java) public class Start { public static void main(String[] args) { MainView vie ...

  8. idea 内置tomcat jersey 跨服务器 上传文件报400错误

    报错内容 com.sun.jersey.api.client.UniformInterfaceException: PUT http://.jpg returned a response status ...

  9. 2022-07-13 第六组 润土 Java01学习笔记

    1.数据类型: 基本数据类型: 整型: byte 字节型 -128-127 1个字节 short 短整型 2个字节 int 整型 4个字节 long 长整型 8个字节 浮点型: float 单精度 4 ...

  10. Solution -「HNOI2013」消毒

    弱化一下,先考虑在二维上解决问题. 题目就转化为:有 \(n\) 个点 \((i, j)\) 需要被覆盖,而我们每次可以选一行或一列去覆盖,求覆盖所有点的最少选择次数. 如果我们对于每一个 \((i, ...