Spring的@PostConstruct和Aware接口實(shí)現(xiàn)原理

@PostConstruct是由CommonAnnotationBeanPostProcessor類實(shí)現(xiàn)的。

一、CommonAnnotationBeanPostProcessor是什么時(shí)候加載進(jìn)去的呢?

我們首先看到CommonAnnotationBeanPostProcessor是spring context下的包,說明是spring自帶的類。我們就大膽猜想,它是spring的創(chuàng)世紀(jì)類,即internal類。我們?cè)趺打?yàn)證呢?我們知道spring自帶的創(chuàng)世紀(jì)類是在下面的構(gòu)造方法里面:

public AnnotationConfigApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

new AnnotatedBeanDefinitionReader的時(shí)候會(huì)調(diào)用:

AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

里面有段代碼會(huì)添加CommonAnnotationBeanPostProcessor類:

// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
        if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

二、CommonAnnotationBeanPostProcessor怎么和@PostConstruct關(guān)聯(lián)上的?

首先看下該類的無參構(gòu)造方法:

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

這個(gè)無參構(gòu)造方法肯定會(huì)在實(shí)例化該類的時(shí)候被調(diào)用。
看到里面有PostConstruct注解了吧。在詳細(xì)看下setInitAnnotationType方法:

public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
        this.initAnnotationType = initAnnotationType;
    }

會(huì)把PostConstruct.class賦值給initAnnotationType屬性。這個(gè)屬性所屬的類為InitDestroyAnnotationBeanPostProcessor,可以看到它實(shí)現(xiàn)了BeanPostProcessor接口。

我們就很容易猜想了,PostConstruct肯定在BeanPostProcessor的兩個(gè)拓展方法其中一個(gè)被執(zhí)行了。

三、驗(yàn)證BeanPostProcessor中哪個(gè)拓展方法調(diào)用了@PostConstruct注解

大不了我們看下InitDestroyAnnotationBeanPostProcessor類的這兩個(gè)方法的實(shí)現(xiàn):

@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;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

很明顯postProcessAfterInitialization這個(gè)方法的實(shí)現(xiàn)直接返回bean,沒做任何處理,排除。我們看下postProcessBeforeInitialization方法。里面有個(gè)findLifecycleMetadata方法得到metadata,然后調(diào)用invokeInitMethods。我們可以猜想出來,metadata肯定是一個(gè)method反射對(duì)象,然后通過反射調(diào)用該方法。是不是有可能findLifecycleMetadata方法,返回的就是@PostConstruct注解的方法呢?

private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
        if (this.lifecycleMetadataCache == null) {
            // Happens after deserialization, during destruction...
            return buildLifecycleMetadata(clazz);
        }
        // Quick check on the concurrent map first, with minimal locking.
        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;
    }

核心方法在buildLifecycleMetadata:

private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
        final boolean debug = logger.isDebugEnabled();
        LinkedList<LifecycleElement> initMethods = new LinkedList<LifecycleElement>();
        LinkedList<LifecycleElement> destroyMethods = new LinkedList<LifecycleElement>();
        Class<?> targetClass = clazz;

        do {
            final LinkedList<LifecycleElement> currInitMethods = new LinkedList<LifecycleElement>();
            final LinkedList<LifecycleElement> currDestroyMethods = new LinkedList<LifecycleElement>();

            ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
                @Override
                public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
                    if (initAnnotationType != null) {
                        if (method.getAnnotation(initAnnotationType) != null) {
                             // PostConstruct 賦值給了initAnnotationType,只要用@PostConstruct修飾的方法,必然會(huì)進(jìn)來。
                            LifecycleElement element = new LifecycleElement(method);
                            currInitMethods.add(element);
                            if (debug) {
                                logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
                            }
                        }
                    }
                    if (destroyAnnotationType != null) {
                        if (method.getAnnotation(destroyAnnotationType) != null) {
                            currDestroyMethods.add(new LifecycleElement(method));
                            if (debug) {
                                logger.debug("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 new LifecycleMetadata(clazz, initMethods, destroyMethods);
    }

看到關(guān)鍵字ReflectionUtils.doWithLocalMethods(class,() -> doWith)了嗎?遍歷class所有的method,執(zhí)行doWith方法。而doWith方法里面出現(xiàn)了最關(guān)鍵的initAnnotationType。是不是關(guān)聯(lián)上了第二節(jié)說的那個(gè)方法了:

public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
        // PostConstruct 賦值給了initAnnotationType
        this.initAnnotationType = initAnnotationType;
    }

最終,bean class所有用@PostConstruct注解修飾的方法,都會(huì)被返回給第三節(jié)中的findLifecycleMetadata方法。如下:

@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;
    }

我們看下metadata.invokeInitMethods方法。

public void invokeInitMethods(Object target, String beanName) throws Throwable {
            Collection<LifecycleElement> initMethodsToIterate =
                    (this.checkedInitMethods != null ? this.checkedInitMethods : this.initMethods);
            if (!initMethodsToIterate.isEmpty()) {
                boolean debug = logger.isDebugEnabled();
                for (LifecycleElement element : initMethodsToIterate) {
                    if (debug) {
                        logger.debug("Invoking init method on bean '" + beanName + "': " + element.getMethod());
                    }
                    element.invoke(target);
                }
            }
        }

element.invoke(target)不就是method.invoke(object)嘛~

四、知道@PostConstruct怎么被調(diào)用了,那它什么時(shí)候被調(diào)用呢?

上節(jié)我們已經(jīng)知道了@PostConstruct被類CommonAnnotationBeanPostProcessor的構(gòu)造函數(shù)添加進(jìn)去的,該類繼承了InitDestroyAnnotationBeanPostProcessor。而它又實(shí)現(xiàn)了BeanPostProcessor接口,并且實(shí)現(xiàn)在postProcessBeforeInitialization方法里面。

我們都知道postProcessBeforeInitialization方法是在doCreatedBean的initializeBean的applyBeanPostProcessorsBeforeInitialization方法里面。如下:

@Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
            throws BeansException {

        Object result = existingBean;
        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
            result = beanProcessor.postProcessBeforeInitialization(result, beanName);
            if (result == null) {
                return result;
            }
        }
        return result;
    }

beanProcessor.postProcessBeforeInitialization方法,可不就有CommonAnnotationBeanPostProcessor嘛~因?yàn)樗莝pring的創(chuàng)世紀(jì)類,由第一節(jié)中的spring自動(dòng)加載進(jìn)去。

所以我們這里可以知道初始化bean的時(shí)候(參考initializeBean方法的實(shí)現(xiàn)),那幾個(gè)初始化方法的執(zhí)行順序了。

invokeAwareMethods -> postProcessBeforeInitialization(ApplicationContextAwareProcessor會(huì)執(zhí)行剩下的aware方法) -> afterPropertiesSet -> initMethod -> postProcessAfterInitialization(AOP)

Spring的Aware接口實(shí)現(xiàn)原理

aware其實(shí)就是spring的回調(diào)方法,用來在某一個(gè)生命周期階段,調(diào)用用戶的回調(diào)方法。

比如:我們創(chuàng)建一個(gè)bean實(shí)現(xiàn)ApplicationContextAware接口,該接口只有一個(gè)方法:setApplicationContext。那么我們的bean既然實(shí)現(xiàn)了該接口,必須重寫該方法,這個(gè)時(shí)候我們就可以在這個(gè)bean里面定義一個(gè)容器,來接收spring回調(diào)給我們的ApplicationContext容器。這樣,咱們就可以拿到整個(gè)spring容器了。

再比如:我們創(chuàng)建一個(gè)bean實(shí)現(xiàn)BeanNameAware接口,那么spring會(huì)在特殊生命周期階段回調(diào)咱們的bean的setBeanName。我們同樣也可以定義一個(gè)String成員屬性來接收這個(gè)beanName。

所以,aware接口給了程序員可以讓spring回調(diào)我們業(yè)務(wù)的口子。比如:我們自己實(shí)現(xiàn)一個(gè)demoAware。由于demoAware并沒有被spring預(yù)先硬編碼進(jìn)去,所以想要spring回調(diào)demoAware的實(shí)現(xiàn)類,我們可以看考ApplicationContextAwareProcessor。咱們可以實(shí)現(xiàn)BeanPostProcessor,在postProcessBeforeInitialization或者postProcessAfterInitialization的方法里面,調(diào)用invokeAwareInterfaces方法。是不是很靈活?。?!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容