• 注解@PostConstruct分析


    作用

    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");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 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对象的方法,把拿回来的对象存入缓存中

    代码展示:

    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.buildLifecycleMetadata方法分析:

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

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

    代码展示:

    private LifecycleMetadata buildLifecycleMetadata(final Class clazz) {
        List initMethods = new ArrayList<>();
        List destroyMethods = new ArrayList<>();
        Class targetClass = clazz;
    
        do {
            final List currInitMethods = new ArrayList<>();
            final List 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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

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

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

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

    public void invokeInitMethods(Object target, String beanName) throws Throwable {
        Collection checkedInitMethods = this.checkedInitMethods;
        Collection initMethodsToIterate = (checkedInitMethods != null ? checkedInitMethods : this.initMethods);
        if (!initMethodsToIterate.isEmpty()) {
            for (LifecycleElement element : initMethodsToIterate) {
                element.invoke(target);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName)
    
    • 1
  • 相关阅读:
    MyBatis入门
    框架之SpringBoot基础(一)
    基本数据类型
    html表格标签的学习,什么是html的表格标签
    金仓KFS数据集中场景(多对一)部署
    R语言绘制IPCC风格箱线抖动点图
    Python Django 零基础从零到一部署服务,Hello Django!全文件夹目录和核心代码!
    spring复习:(60)自定义qualifier
    一起Talk Android吧(第三百六十四回:多线程之同步块)
    如何恢复被.carver勒索病毒加密的数据?
  • 原文地址:https://blog.csdn.net/m0_70748381/article/details/126886184