• 注解@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");
    }
    复制代码

      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 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.既然是在初始化前的处理器中调用,而且源于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 checkedInitMethods = this.checkedInitMethods;
        Collection initMethodsToIterate = (checkedInitMethods != null ? checkedInitMethods : this.initMethods);
        if (!initMethodsToIterate.isEmpty()) {
            for (LifecycleElement element : initMethodsToIterate) {
                element.invoke(target);
            }
        }
    }
    复制代码

     

        

     

     

     

    postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName)
  • 相关阅读:
    设计模式简介
    Ubuntu 1804 ModuleNotFoundError: No module named ‘OpenSSL‘ in Python
    EquiVSet
    C++ map容器用法
    react-router-dom V5版本 路由搭建
    CAPL语言编译的那些事
    明明加了唯一索引,为什么还是产生重复数据?
    【23-24 秋学期】NNDL 作业5 第四章课后题
    开源聚力,共创未来 | 麒麟信安祝贺openKylin首个体验版正式发布!
    Python API+Postman+jmeter
  • 原文地址:https://www.cnblogs.com/chafry/p/16697234.html