亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Spring AOP 源碼初窺(二) 從注解開始

Amio / 2320人閱讀

摘要:版本從注解開始由于在本人實(shí)際應(yīng)用中使用的是注解配置,也更傾向于了解的整個(gè)實(shí)現(xiàn),而不僅僅是關(guān)鍵實(shí)現(xiàn)。于是本篇源碼解析,將會(huì)從注解開始。那么,便從的源碼引用開始吧。的引用先從源碼中找有引用到,用來判斷是否有該注解的代碼。

版本

spring 5.0.8.BUILD-SNAPSHOT

aspectjweaver 1.8.13

從注解開始

由于在本人實(shí)際應(yīng)用中使用的是注解配置AOP,也更傾向于了解Spring AOP的整個(gè)實(shí)現(xiàn),而不僅僅是關(guān)鍵實(shí)現(xiàn)。于是本篇源碼解析,將會(huì)從注解開始。了解Spring AOP是怎么掃描Aspect配置,匹配,并生成AOP代理的。

注解@Aspect定了一個(gè)類為AOP的配置。那么,便從@Aspect的源碼引用開始吧。

@Aspect的引用

先從源碼中找有引用到@Aspect,用來判斷Class是否有該注解的代碼。找到方法。

/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java
...
@Override
public boolean isAspect(Class clazz) {
    return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}

private boolean hasAspectAnnotation(Class clazz) {
    return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}

/**
 * We need to detect this as "code-style" AspectJ aspects should not be
 * interpreted by Spring AOP.
 */
private boolean compiledByAjc(Class clazz) {
    // The AJTypeSystem goes to great lengths to provide a uniform appearance between code-style and
    // annotation-style aspects. Therefore there is no "clean" way to tell them apart. Here we rely on
    // an implementation detail of the AspectJ compiler.
    for (Field field : clazz.getDeclaredFields()) {
        if (field.getName().startsWith(AJC_MAGIC)) {
            return true;
        }
    }
    return false;
}
...

isAspect(Class clazz)用來判斷clazz對(duì)象是否包含Aspect.class注解并且未被AspectJ編譯過,其中hasAspectAnnotation(Class clazz)內(nèi)容很明顯就不多提。倒是compiledByAjc(Class clazz)的實(shí)現(xiàn)比較特別。它的實(shí)現(xiàn)是用字段前綴來判斷是否為"code-style" aspects,看起來是一種比較Hack的方法。

這里我有一個(gè)疑惑點(diǎn),就是"code-style" aspects和"annotation-style" aspects的具體所指,查了一圈也沒有看到明確的解釋。只在IDEA的幫助文檔Overview of AspectJ support這段上有看到相關(guān)的解釋。我的理解是"code-style"是由AspectJ Language所定義的aspect,會(huì)由AspectJ來編譯,而"annotation-style"則是由使用了@Aspect注解的Java語言所定義的aspect,如有錯(cuò)誤煩請(qǐng)指出。
入口在Bean的生命周期中

通過一步步閱讀和調(diào)試,可以一層一層向上找到org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java中有兩個(gè)入口。

postProcessBeforeInstantiation和postProcessAfterInitialization,是Bean生命周期中的兩個(gè)步驟:

postProcessBeforeInstantiation: 在Bean實(shí)例化之前執(zhí)行

postProcessAfterInitialization: 在Bean初始化之后執(zhí)行

postProcessBeforeInstantiation:
/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java
...
@Override
public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {
    Object cacheKey = getCacheKey(beanClass, beanName);

    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }

    // Create proxy here if we have a custom TargetSource.
    // Suppresses unnecessary default instantiation of the target bean:
    // The TargetSource will handle target instances in a custom fashion.
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    return null;
}
...

這個(gè)方法的目的是將含有custom TargetSource的bean進(jìn)行增強(qiáng)處理??煞譃閮刹糠?,前半部分利用緩存和幾個(gè)方法判斷是否需要增強(qiáng)。后半部分則進(jìn)入主題判斷是否含有custom TargetSource。不過這里我對(duì)custom TargetSource不是特別理解,也沒有細(xì)看,因?yàn)橥ㄟ^@Aspect注解配置不會(huì)執(zhí)行這里面的代碼,留著以后有時(shí)間再看。
這里還有另外兩個(gè)方法:

isInfrastructureClass(是否是基礎(chǔ)類,如Advice、Pointcut、Advisor、AopInfrastructureBean 及其超類)

shouldSkip(主要目的是判斷是否是已注冊(cè)的@Aspect配置Bean,其實(shí)掃描@Aspect注解配置的方法就在這里面被調(diào)用到了,這個(gè)后面再說)

postProcessAfterInitialization
/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java
....
/**
 * Create a proxy with the configured interceptors if the bean is
 * identified as one to proxy by the subclass.
 * @see #getAdvicesAndAdvisorsForBean
 */
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

/**
 * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
 * @param bean the raw bean instance
 * @param beanName the name of the bean
 * @param cacheKey the cache key for metadata access
 * @return a proxy wrapping the bean, or the raw bean instance as-is
 */
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

可以看到關(guān)鍵內(nèi)容就在wrapIfNecessary里面。顧名思義:必要時(shí)轉(zhuǎn)成AOP代理。前半部分判斷是否是不需要增強(qiáng)的,跟postProcessBeforeInstantiation的前半部分有點(diǎn)類似。后半部分根據(jù)是否有合適的Advice方法,有則將Bean轉(zhuǎn)成代理。
好了,這里其實(shí)就是整個(gè)流程最關(guān)鍵的兩個(gè)地方了:

getAdvicesAndAdvisorsForBean(獲取適合該Bean的Advice方法,里面包含了掃描@Aspect注解配置Bean的方法)

createProxy(創(chuàng)建AOP代理,里面包含了AOP代理的實(shí)現(xiàn))

這兩個(gè)方法的具體內(nèi)容,將在接下來的文章介紹

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/76764.html

相關(guān)文章

  • Spring AOP 源碼初窺(一) 概念

    摘要:而面向切面編程理所當(dāng)然關(guān)注于切面,那么什么是切面可以理解為程序執(zhí)行時(shí)的某個(gè)節(jié)點(diǎn),或更具體一點(diǎn),在某個(gè)方法執(zhí)行之前,執(zhí)行之后,返回之后等其它節(jié)點(diǎn)。術(shù)語一個(gè)切面,可以理解為一個(gè)切面模塊,將相關(guān)的增強(qiáng)內(nèi)容寫進(jìn)同一個(gè)切面。例如一個(gè)負(fù)責(zé)日志的切面。 AOP是什么 AOP全稱 Aspect-Oriented Programming 即面向切面編程。怎么樣,是不是感覺很熟悉?對(duì),類似的還有面向過程編...

    CarterLi 評(píng)論0 收藏0
  • Spring AOP 源碼初窺(三)掃描Advice與Bean匹配

    摘要:版本如何掃描接上一回,講到了方法,該方法的目的是獲取并生成。其中英文為源碼注釋。那么,以上便是通過掃描配置并生成的過程了。一些總結(jié)讀到這兒,如何掃描配置,生成類,并匹配對(duì)應(yīng)的整個(gè)流程已經(jīng)很清楚了。 版本 spring 5.0.8.BUILD-SNAPSHOT aspectjweaver 1.8.13 如何掃描Advice 接上一回,講到了getAdvicesAndAdvisorsF...

    oysun 評(píng)論0 收藏0
  • 【好好面試】手把手調(diào)試,教你分析Spring-Aop

    摘要:思考之所以會(huì)選擇為切入點(diǎn),是因?yàn)橥ㄟ^命名可以看出這是用來構(gòu)建代理強(qiáng)化對(duì)象的地方,并且由于是先將目標(biāo)類加載到內(nèi)存中,之后通過修改字節(jié)碼生成目標(biāo)類的子類,因此我猜測強(qiáng)化是在目標(biāo)類實(shí)例化后觸發(fā)的時(shí)候進(jìn)行的。 【干貨點(diǎn)】 此處是【好好面試】系列文的第11篇文章??赐暝撈恼?,你就可以了解Spring中Aop的相關(guān)使用和原理,并且能夠輕松解答Aop相關(guān)的面試問題。更重要的是,很多人其實(shí)一看源碼就...

    aervon 評(píng)論0 收藏0
  • 學(xué)Aop?看這篇文章就夠了?。?!

    摘要:又是什么其實(shí)就是一種實(shí)現(xiàn)動(dòng)態(tài)代理的技術(shù),利用了開源包,先將代理對(duì)象類的文件加載進(jìn)來,之后通過修改其字節(jié)碼并且生成子類。 在實(shí)際研發(fā)中,Spring是我們經(jīng)常會(huì)使用的框架,畢竟它們太火了,也因此Spring相關(guān)的知識(shí)點(diǎn)也是面試必問點(diǎn),今天我們就大話Aop。特地在周末推文,因?yàn)樵撈恼麻喿x起來還是比較輕松詼諧的,當(dāng)然了,更主要的是周末的我也在充電學(xué)習(xí),希望有追求的朋友們也盡量不要放過周末時(shí)...

    boredream 評(píng)論0 收藏0
  • 徹底征服 Spring AOP 之 實(shí)戰(zhàn)篇

    摘要:接上一小節(jié)徹底征服之理論篇實(shí)戰(zhàn)看了上面這么多的理論知識(shí)不知道大家有沒有覺得枯燥哈不過不要急俗話說理論是實(shí)踐的基礎(chǔ)對(duì)有了基本的理論認(rèn)識(shí)后我們來看一下下面幾個(gè)具體的例子吧下面的幾個(gè)例子是我在工作中所遇見的比較常用的的使用場景我精簡了很多有干擾我 接上一小節(jié)徹底征服 Spring AOP 之 理論篇 Spring AOP 實(shí)戰(zhàn) 看了上面這么多的理論知識(shí), 不知道大家有沒有覺得枯燥哈. 不過不...

    CNZPH 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<