AOP源碼分析之proxy對(duì)象的創(chuàng)建

通過(guò)上節(jié)我們了解了AnnotationAwareAspectJAutoProxyCreator的其中之一的作用霜浴,是作為一個(gè)后置處理器在我們創(chuàng)建單實(shí)例bean之前攔截嘗試著先去創(chuàng)建代理對(duì)象,如果是找到了直接返回瘪板,當(dāng)然它作為此類(lèi)型的【InstantiationAwareBeanPostProcessor】的后置處理器跟我們之前的BeanPostProcessor【后置處理器】是有區(qū)別的:

區(qū)別

兩者最大的區(qū)別在于創(chuàng)建bean的執(zhí)行的時(shí)機(jī)不同

  • BeanPostProcessor:是在我們初始化bean的前后進(jìn)行相關(guān)的操作
  • InstantiationAwareBeanPostProcessor:是在我們bean的創(chuàng)建之前進(jìn)行攔截烛卧,然后自己嘗試著去創(chuàng)建代理對(duì)象,如果存在直接使用此代理對(duì)象

所以說(shuō),spring中的每一種類(lèi)型的BeanPostProcessor都有自己的執(zhí)行時(shí)機(jī)绞佩,這也是對(duì)于我們是一個(gè)難點(diǎn),接著我們來(lái)說(shuō)AnnotationAwareAspectJAutoProxyCreator的另外一個(gè)作用猪钮,首先我們?cè)賮?lái)復(fù)習(xí)一下它的類(lèi)圖:

image

通過(guò)它的繼承和實(shí)現(xiàn)關(guān)系品山,我們還會(huì)發(fā)現(xiàn)AnnotationAwareAspectJAutoProxyCreator的父類(lèi)AbstractAutoProxyCreator實(shí)現(xiàn)了BeanFactoryAware此接口,那么必然會(huì)實(shí)現(xiàn)該接口的#setBeanFactory(...)方法

  • 在我們的頂級(jí)父類(lèi)AbstractAutoProxyCreator中有這樣的一段代碼:
 public void setBeanFactory(BeanFactory beanFactory) {
    this.beanFactory = beanFactory;
}
  • 同樣不難猜測(cè)在它的子類(lèi)AbstractAdvisorAutoProxyCreator中:
@Override
public void setBeanFactory(BeanFactory beanFactory) {
    super.setBeanFactory(beanFactory);
    if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
        throw new IllegalArgumentException(
                "AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
    }
    initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}

發(fā)現(xiàn)子類(lèi)重寫(xiě)了setBeanFactory(....)方法烤低,說(shuō)了這么多肘交,我們其主要關(guān)注的核心還需要放在頂級(jí)分類(lèi)AbstractAutoProxyCreator中來(lái)完成接下來(lái)的分析,現(xiàn)在我們要把關(guān)注的核心點(diǎn)來(lái)放在我們自己編寫(xiě)的業(yè)務(wù)類(lèi)和日志切面類(lèi)的創(chuàng)建

AbstractAutoProxyCreator

在這個(gè)類(lèi)中扑馁,它既扮演了postProcessor的角色也扮演了BeanFactoryAware的角色涯呻,至于BeanFactoryAware角色來(lái)講我們已經(jīng)知道它重寫(xiě)了setBeanFactory(...)方法,不必多說(shuō)檐蚜,我們?cè)贏bstractAutoProxyCreator類(lèi)中會(huì)發(fā)現(xiàn)#postProcessBeforeInstantiation(...)和#postProcessAfterInstantiation(...)這兩個(gè)方法值得我們注意下魄懂,我們給他打上斷點(diǎn),首先分析的入口還是我們的測(cè)試類(lèi):

 //Aop測(cè)試
@Test
public void testAop(){
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAop.class);
    MathCalculator calculator = applicationContext.getBean(MathCalculator.class);
    calculator.div(10,5);

    applicationContext.close();
}

跟蹤代碼我們來(lái)到AbstractApplicatContext#refresh()方法闯第,我們一步一步Dbug當(dāng)來(lái)到this.registerBeanPostProcessors(beanFactory)此處是市栗,斷點(diǎn)進(jìn)入我們的AbstractAutoProxyCreator#setBeanFactory(...)方法,直接跳過(guò)來(lái)到refresh()方法咳短,接著當(dāng)斷點(diǎn)來(lái)到this.finishBeanFactoryInitialization(beanFactory)時(shí)跳到AbstractAutoProxyCreator#postProcessBeforeInstantiation(....)方法上填帽,那么我們?cè)诖藭r(shí)進(jìn)行分析,當(dāng)然這里只關(guān)心我們自己寫(xiě)的bean的創(chuàng)建具體如下圖:

image.png

當(dāng)我們執(zhí)行完postProcessBeforeInstantiation方法之后會(huì)執(zhí)行postProcessAfterInstantiation方法咙好,兩個(gè)方法交替執(zhí)行篡腌,多提了一點(diǎn),回歸正題:

  • 首先獲取當(dāng)前的bean的名字
  Object cacheKey = getCacheKey(beanClass, beanName);
  • 通過(guò)如下的方式來(lái)判斷當(dāng)前bean是否在advisedBeans中存在
private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);


 if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }

其中advisedBeans 保存了所有需要增強(qiáng)的bean勾效,因?yàn)榇丝涛覀兊男枰鰪?qiáng)的業(yè)務(wù)類(lèi)添加進(jìn)此緩存中嘹悼,所以直接跳過(guò)此判斷來(lái)到:

  • 通過(guò)如下的判斷當(dāng)前bean是否是一個(gè)基礎(chǔ)類(lèi)型的bean
  if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }

通過(guò)方法#isInfrastructureClass(beanClass)來(lái)判斷是否是一個(gè)基礎(chǔ)類(lèi)型的叛甫,那什么是基礎(chǔ)類(lèi)型的bean,跟蹤代碼來(lái)到:

  protected boolean isInfrastructureClass(Class<?> beanClass) {
    return super.isInfrastructureClass(beanClass) || this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass);
}

這里我們看到的是調(diào)用了父類(lèi)的super.isInfrastructureClass(beanClass)繼續(xù)跟蹤代碼來(lái)到:

 protected boolean isInfrastructureClass(Class<?> beanClass) {
    boolean retVal = Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass) || AopInfrastructureBean.class.isAssignableFrom(beanClass);
    if (retVal && this.logger.isTraceEnabled()) {
        this.logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
    }

    return retVal;
}

這里就明確了杨伙,原來(lái)基礎(chǔ)類(lèi)型是Advice其监、Pointcut、Advisor限匣、AopInfrastructureBean這些類(lèi)型抖苦,我們的邏輯類(lèi)肯定不是這些基礎(chǔ)類(lèi)型,直接放行來(lái)到上層米死,其中我們注意一點(diǎn):this.aspectJAdvisorFactory.isAspect(beanClass)是這個(gè)類(lèi)型的锌历,繼續(xù)跟蹤代碼來(lái)到:

 public boolean isAspect(Class<?> clazz) {
    return this.hasAspectAnnotation(clazz) && !this.compiledByAjc(clazz);
}

接著繼續(xù)跟蹤代碼來(lái)到:

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

從這里看到,我們的基礎(chǔ)類(lèi)型還包括注解@Aspect,接著來(lái)到我們的方法#postProcessBeforeInstantiation()開(kāi)始位置

  • 同時(shí)通過(guò)this.shouldSkip(beanClass, beanName)來(lái)判斷是否需要跳過(guò)

  • 通過(guò)下面代碼來(lái)判斷是否需要在此處創(chuàng)建代理

TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }

在這里創(chuàng)建代理對(duì)象的前提時(shí)我們已經(jīng)自定義代理的目標(biāo)對(duì)象峦筒,很顯然我們是沒(méi)有的究西,直接跳過(guò)來(lái)到#postProcessAfterInitialization(....)方法:

image.png
 public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return this.wrapIfNecessary(bean, beanName, cacheKey);
        }
    }

    return bean;
}

其中方法this.wrapIfNecessary(bean, beanName, cacheKey)需要我們注意下,意思是如果需要包裝的情況下會(huì)調(diào)用此方法勘天,我們繼續(xù)跟蹤代碼:

 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    } else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    } else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
        Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        } else {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
    } else {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }
}

簡(jiǎn)單的分析下上述代碼的過(guò)程:

  • 通過(guò)!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)來(lái)判斷當(dāng)前bean是否是基礎(chǔ)類(lèi)型的和是否需要跳過(guò)
  • 通過(guò)如下代碼來(lái)獲取當(dāng)前bean的所有增強(qiáng)器(也就是通知方法)specificInterceptors
 getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource)

跟蹤代碼來(lái)到此方法:

@Nullable
  protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    List<Advisor> advisors = this.findEligibleAdvisors(beanClass, beanName);
    return advisors.isEmpty() ? DO_NOT_PROXY : advisors.toArray();
}
image.png

發(fā)現(xiàn)通過(guò)繼續(xù)調(diào)用內(nèi)部的方法#this.findEligibleAdvisors(beanClass, beanName);其中參數(shù)為上圖中紅色框內(nèi)的怔揩,繼續(xù)跟蹤代碼來(lái)到:

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    List<Advisor> candidateAdvisors = this.findCandidateAdvisors();
    List<Advisor> eligibleAdvisors = this.findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    this.extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = this.sortAdvisors(eligibleAdvisors);
    }

    return eligibleAdvisors;
}
  • 首先一進(jìn)方法將獲取到的后補(bǔ)增強(qiáng)器存放咋list中【candidateAdvisors 】


    image.png
  • 接著是通過(guò)如下的代碼是獲取能作用于我們當(dāng)前bean的增強(qiáng)器

  List<Advisor> eligibleAdvisors = this.findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);

我們來(lái)看看#findAdvisorsThatCanApply(...)是如何查找的過(guò)程

  protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    ProxyCreationContext.setCurrentProxiedBeanName(beanName);

    List var4;
    try {
        var4 = AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    } finally {
        ProxyCreationContext.setCurrentProxiedBeanName((String)null);
    }

    return var4;
}
  • 首先一進(jìn)方法將當(dāng)前 要增強(qiáng)的bean進(jìn)行了設(shè)置

  • 接著通過(guò)Aop的工具去查找,最后進(jìn)行返回

  • 接著通過(guò)如下方法對(duì)我們的增強(qiáng)器進(jìn)行排序操作

  this.sortAdvisors(eligibleAdvisors);

下圖所示的最終排序之后的增強(qiáng)器

image.png

其實(shí)就是我們自己編寫(xiě)的切面那些方法脯丝,繼續(xù)跟蹤代碼:

  • 將當(dāng)前需要增強(qiáng)的bean添加到advisedBeans 中商膊,通過(guò)下面代碼:
   this.advisedBeans.put(cacheKey, Boolean.TRUE);
  • 如果當(dāng)前bean需要增強(qiáng)的話,就為它進(jìn)行代理對(duì)象的創(chuàng)建
Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

繼續(xù)跟蹤代碼來(lái)到AbstractAutoProxyCreator類(lèi)中的#createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource)方法宠进,我們來(lái)看看具體代碼創(chuàng)建邏輯過(guò)程:

 ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this);
    if (!proxyFactory.isProxyTargetClass()) {
        if (this.shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        } else {
            this.evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }
image.png

圖中是上述的方法中用到的參數(shù)類(lèi)型晕拆,需要我們來(lái)注意的一點(diǎn)是 this.evaluateProxyInterfaces(beanClass, proxyFactory)此方法,此方法主要的目的是將當(dāng)前bean的類(lèi)型設(shè)置為一個(gè)ProxyFactory

  • 通過(guò)如下代碼來(lái)獲取當(dāng)前bean所有的通知方法(增強(qiáng)器)
  Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
  • 接著是保存到proxyFactory中
  proxyFactory.addAdvisors(advisors);
  • 接著通過(guò)如下的代碼進(jìn)行代理對(duì)象的真正創(chuàng)建過(guò)程:
  proxyFactory.getProxy(this.getProxyClassLoader());

跟蹤代碼來(lái)到:

  public Object getProxy(@Nullable ClassLoader classLoader) {
    return this.createAopProxy().getProxy(classLoader);
}

繼續(xù)看我們的createAopProxy()方法

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
        return new JdkDynamicAopProxy(config);
    } else {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.");
        } else {
            return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
        }
    }
}

通過(guò)上面的代碼spring自動(dòng)幫我們創(chuàng)建了ObjenesisCglibAopProxy 類(lèi)型的CGLIB代理材蹬,最后一路返回來(lái)到我們AbstractAutoProxyCreator類(lèi)中的#wrapIfNecessary()方法

  • 通過(guò)如下操作將當(dāng)前要增強(qiáng)的組件代理對(duì)象的class類(lèi)型返回給容器中
  this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;

這樣做的目的是我們下節(jié)要說(shuō)的实幕,通過(guò)創(chuàng)建的代理對(duì)象來(lái)執(zhí)行我們的目標(biāo)方法,那么關(guān)于AOP代理對(duì)象的創(chuàng)建分析就到這了....

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末堤器,一起剝皮案震驚了整個(gè)濱河市昆庇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌闸溃,老刑警劉巖整吆,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異辉川,居然都是意外死亡表蝙,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén)乓旗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)府蛇,“玉大人,你說(shuō)我怎么就攤上這事屿愚』憧纾” “怎么了务荆?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)扰法。 經(jīng)常有香客問(wèn)我蛹含,道長(zhǎng),這世上最難降的妖魔是什么塞颁? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮吸耿,結(jié)果婚禮上祠锣,老公的妹妹穿的比我還像新娘。我一直安慰自己咽安,他們只是感情好伴网,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著妆棒,像睡著了一般澡腾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上糕珊,一...
    開(kāi)封第一講書(shū)人閱讀 51,775評(píng)論 1 307
  • 那天动分,我揣著相機(jī)與錄音,去河邊找鬼红选。 笑死澜公,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的喇肋。 我是一名探鬼主播坟乾,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蝶防!你這毒婦竟也來(lái)了甚侣?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤间学,失蹤者是張志新(化名)和其女友劉穎殷费,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體菱鸥,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宗兼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了氮采。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片殷绍。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鹊漠,靈堂內(nèi)的尸體忽然破棺而出主到,到底是詐尸還是另有隱情茶行,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布登钥,位于F島的核電站畔师,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏牧牢。R本人自食惡果不足惜看锉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望塔鳍。 院中可真熱鬧伯铣,春花似錦、人聲如沸轮纫。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)掌唾。三九已至放前,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間糯彬,已是汗流浹背凭语。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留情连,地道東北人叽粹。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像却舀,于是被迫代替她去往敵國(guó)和親虫几。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356