<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring中AOP相關(guān)的API及源碼解析,原來AOP是這樣子的

          共 33045字,需瀏覽 67分鐘

           ·

          2020-07-28 12:37


          ?


          本系列文章:

          讀源碼,我們可以從第一行讀起

          你知道Spring是怎么解析配置類的嗎?

          配置類為什么要添加@Configuration注解?

          談?wù)凷pring中的對(duì)象跟Bean,你知道Spring怎么創(chuàng)建對(duì)象的嗎?

          這篇文章,我們來談一談Spring中的屬性注入

          推薦閱讀:

          Spring官網(wǎng)閱讀 | 總結(jié)篇

          Spring雜談

          本系列文章將會(huì)帶你一行行的將Spring的源碼吃透,推薦閱讀的文章是閱讀源碼的基礎(chǔ)!

          因?yàn)楸疚臅?huì)涉及到動(dòng)態(tài)代理的相關(guān)內(nèi)容,如果對(duì)動(dòng)態(tài)代理不是很了解的話,參考文章:

          動(dòng)態(tài)代理學(xué)習(xí)(一)自己動(dòng)手模擬JDK動(dòng)態(tài)代理

          動(dòng)態(tài)代理學(xué)習(xí)(二)JDK動(dòng)態(tài)代理源碼分析

          前言

          之所以寫這么一篇文章主要是因?yàn)橄缕恼聦⒔Y(jié)束Spring啟動(dòng)整個(gè)流程的分析,從解析配置到創(chuàng)建對(duì)象再到屬性注入最后再將創(chuàng)建好的對(duì)象初始化成為一個(gè)真正意義上的Bean。因?yàn)橄缕恼聲?huì)涉及到AOP,所以提前單獨(dú)將AOP的相關(guān)API及源碼做一次解讀,這樣可以降低閱讀源碼的障礙,話不多說,我們進(jìn)入正文!

          一個(gè)使用API創(chuàng)建代理的例子

          在進(jìn)入API分析前,我們先通過兩個(gè)例子體會(huì)下如何使用API的方式來創(chuàng)建一個(gè)代理對(duì)象,對(duì)應(yīng)示例如下:

          1. 定義通知
          public?class?DmzAfterReturnAdvice?implements?AfterReturningAdvice?{
          ?@Override
          ?public?void?afterReturning(@Nullable?Object?returnValue,?Method?method,?Object[]?args,?@Nullable?Object?target)?throws?Throwable?{
          ??System.out.println("after?invoke?method?["?+?method.getName()?+?"],aop?afterReturning?logic?invoked");
          ?}
          }

          public?class?DmzAroundAdvice?implements?MethodInterceptor?{
          ?@Override
          ?public?Object?invoke(MethodInvocation?invocation)?throws?Throwable?{
          ??System.out.println("aroundAdvice?invoked");
          ??return?invocation.proceed();
          ?}
          }

          public?class?DmzBeforeAdvice?implements?MethodBeforeAdvice?{
          ?@Override
          ?public?void?before(Method?method,?Object[]?args,?Object?target)?throws?Throwable?{
          ??System.out.println("before?invoke?method?["?+?method.getName()?+?"],aop?before?logic?invoked");
          ?}
          }

          public?class?DmzIntroductionAdvice?extends?DelegatingIntroductionInterceptor?implements?Runnable?{
          ?@Override
          ?public?void?run()?{
          ??System.out.println("running!!!!");
          ?}
          }
          1. 切點(diǎn)
          public?class?DmzPointcut?implements?Pointcut?{
          ?@Override
          ?@NonNull
          ?public?ClassFilter?getClassFilter()?{
          ??//?在類級(jí)別上不進(jìn)行攔截
          ??return?ClassFilter.TRUE;
          ?}

          ?@Override
          ?@NonNull
          ?public?MethodMatcher?getMethodMatcher()?{
          ??return?new?StaticMethodMatcherPointcut()?{
          ???@Override
          ???public?boolean?matches(@NonNull?Method?method,?Class?targetClass)?{
          ????//?對(duì)于toString方法不進(jìn)行攔截
          ????return?!method.getName().equals("toString");
          ???}
          ??};
          ?}
          }
          1. 目標(biāo)類
          public?class?DmzService?{
          ?@Override
          ?public?String?toString()?{
          ??System.out.println("dmzService?toString?invoke");
          ??return?"dmzService";
          ?}

          ?public?void?testAop(){
          ??System.out.println("testAop?invoke");
          ?}
          }
          1. 測(cè)試代碼
          public?class?Main?{
          ?public?static?void?main(String[]?args)?{

          ??ProxyFactory?proxyFactory?=?new?ProxyFactory();

          ??//?一個(gè)Advisor代表的是一個(gè)已經(jīng)跟指定切點(diǎn)綁定了的通知
          ????????//?在這個(gè)例子中意味著環(huán)繞通知不會(huì)作用到toString方法上
          ??Advisor?advisor?=?new?DefaultPointcutAdvisor(new?DmzPointcut(),?new?DmzAroundAdvice());

          ??//?添加一個(gè)綁定了指定切點(diǎn)的環(huán)繞通知
          ??proxyFactory.addAdvisor(advisor);

          ??//?添加一個(gè)返回后的通知
          ??proxyFactory.addAdvice(new?DmzAfterReturnAdvice());

          ??//?添加一個(gè)方法執(zhí)行前的通知
          ??proxyFactory.addAdvice(new?DmzBeforeAdvice());

          ??//?為代理類引入一個(gè)新的需要實(shí)現(xiàn)的接口--Runnable
          ??proxyFactory.addAdvice(new?DmzIntroductionAdvice());

          ??//?設(shè)置目標(biāo)類
          ??proxyFactory.setTarget(new?DmzService());

          ??//?因?yàn)橐獪y(cè)試代理對(duì)象自己定義的方法,所以這里啟用cglib代理
          ??proxyFactory.setProxyTargetClass(true);

          ??//?創(chuàng)建代理對(duì)象
          ??Object?proxy?=?proxyFactory.getProxy();

          ??//?調(diào)用代理類的toString方法,通過控制臺(tái)查看代理邏輯的執(zhí)行情況
          ??proxy.toString();

          ??if?(proxy?instanceof?DmzService)?{
          ???((DmzService)?proxy).testAop();
          ??}

          ??//?判斷引入是否成功,并執(zhí)行引入的邏輯
          ??if?(proxy?instanceof?Runnable)?{
          ???((Runnable)?proxy).run();
          ??}
          ?}
          }

          這里我就不將測(cè)試結(jié)果放出來了,大家可以先自行思考這段程序?qū)⑤敵鍪裁础=酉聛砦覀兙蛠矸治錾厦孢@段程序中所涉及到的API,通過這些API的學(xué)習(xí)相信大家可以徹底理解上面這段代碼。

          API介紹

          Pointcut(切點(diǎn))

          對(duì)應(yīng)接口定義如下:

          public?interface?Pointcut?{
          ?
          ????//?ClassFilter,在類級(jí)別進(jìn)行過濾
          ?ClassFilter?getClassFilter();
          ????
          ?//?MethodMatcher,在方法級(jí)別進(jìn)行過濾
          ?MethodMatcher?getMethodMatcher();
          ?
          ????//?一個(gè)單例對(duì)象,默認(rèn)匹配所有
          ?Pointcut?TRUE?=?TruePointcut.INSTANCE;

          }

          切點(diǎn)的主要作用是定義通知所要應(yīng)用到的類跟方法,上面的接口定義也很明顯的體現(xiàn)了這一點(diǎn),我們可以將其拆分成為兩個(gè)部分

          • ClassFilter,接口定義如下:
          public?interface?ClassFilter?{

          ?boolean?matches(Class?clazz);

          ?ClassFilter?TRUE?=?TrueClassFilter.INSTANCE;

          }

          ClassFilter的主要作用是在類級(jí)別上對(duì)通知的應(yīng)用進(jìn)行一次過濾,如果它的match方法對(duì)任意的類都返回true的話,說明在類級(jí)別上我們不需要過濾,這種情況下,通知的應(yīng)用,就完全依賴MethodMatcher的匹配結(jié)果。

          • MethodMatcher,接口定義如下:
          public?interface?MethodMatcher?{

          ?boolean?matches(Method?method,?@Nullable?Class?targetClass);

          ?boolean?isRuntime();

          ?boolean?matches(Method?method,?@Nullable?Class?targetClass,?Object...?args);

          ?MethodMatcher?TRUE?=?TrueMethodMatcher.INSTANCE;

          }

          MethodMatcher中一共有三個(gè)核心方法

          • matches(Method method, @Nullable Class targetClass),這個(gè)方法用來判斷當(dāng)前定義的切點(diǎn)跟目標(biāo)類中的指定方法是否匹配,它可以在創(chuàng)建代理的時(shí)候就被調(diào)用,從而決定是否需要進(jìn)行代理,這樣就可以避免每次方法執(zhí)行的時(shí)候再去做判斷
          • isRuntime(),如果這個(gè)方法返回true的話,意味著每次執(zhí)行方法時(shí)還需要做一次匹配
          • matches(Method method, @Nullable Class targetClass, Object... args),當(dāng)之前的isRuntime方法返回true時(shí),會(huì)調(diào)用這個(gè)方法再次進(jìn)行一次判斷,返回false的話,意味這個(gè)不對(duì)這個(gè)方法應(yīng)用通知

          Advice(通知)

          環(huán)繞通知(Interception Around Advice)

          接口定義如下:

          public?interface?MethodInterceptor?extends?Interceptor?{

          ????Object?invoke(MethodInvocation?invocation)?throws?Throwable;
          }

          在上面接口定義的invoke方法中,MethodInvocation就是當(dāng)前執(zhí)行的方法,當(dāng)我們調(diào)用invocation.proceed就是在執(zhí)行當(dāng)前的這個(gè)方法,基于此,我們可以在方法的執(zhí)行前后去插入我們自定義的邏輯,比如下面這樣

          //?執(zhí)行前的邏輯
          doSomeThingBefore();
          Object?var?=?invocation.proceed;
          doSomeThingAfter();
          //?執(zhí)行后的邏輯
          retrun?var;

          前置通知(Before Advice)

          public?interface?MethodBeforeAdvice?extends?BeforeAdvice?{

          ????void?before(Method?m,?Object[]?args,?Object?target)?throws?Throwable;
          }

          跟環(huán)繞通知不同的是,這個(gè)接口中定義的方法的返回值是void,所以前置通知是無法修改方法的返回值的。

          如果在前置通知中發(fā)生了異常,那么會(huì)直接終止目標(biāo)方法的執(zhí)行以及打斷整個(gè)攔截器鏈的執(zhí)行

          后置通知(After Returning Advice)

          public?interface?AfterReturningAdvice?extends?Advice?{

          ????void?afterReturning(Object?returnValue,?Method?m,?Object[]?args,?Object?target)
          ????????????throws?Throwable
          ;
          }

          后置通知相比較于前置通知,主要有以下幾點(diǎn)不同

          • 后置通知可以訪問目標(biāo)方法的返回值,但是不能修改
          • 后置通知是在方法執(zhí)行完成后執(zhí)行

          異常通知(Throws Advice)

          public?interface?ThrowsAdvice?extends?AfterAdvice?{

          }

          異常通知中沒有定義任何方法,它更像一個(gè)標(biāo)記接口。我們?cè)诙x異常通知時(shí)需要實(shí)現(xiàn)這個(gè)接口,同時(shí)方法的簽名也有要求

          1. 方法名稱必須是afterThrowing
          2. 方法的參數(shù)個(gè)數(shù)必須是1個(gè)或者4個(gè),如下:
          public?class?OneParamThrowsAdvice?implements?ThrowsAdvice?{

          ????//?如果只有一個(gè)參數(shù),那么這個(gè)參數(shù)必須是要進(jìn)行處理的異常
          ????public?void?afterThrowing(RemoteException?ex)?throws?Throwable?{
          ????????//?Do?something?with?remote?exception
          ????}
          }

          public?class?FourParamThrowsAdvice?implements?ThrowsAdvice?{
          ?
          ????//?如果定義了四個(gè)參數(shù),那么這四個(gè)參數(shù)分別是
          ????// 1.m:目標(biāo)方法
          ????// 2.args:執(zhí)行目標(biāo)方法所需要的參數(shù)
          ????// 3.target:目標(biāo)對(duì)象
          ????// 4.ex:具體要處理的異常
          ????//?并且參數(shù)類型必須按照這個(gè)順序定義
          ????public?void?afterThrowing(Method?m,?Object[]?args,?Object?target,?ServletException?ex)?{
          ????????//?Do?something?with?all?arguments
          ????}
          }

          我們可以在一個(gè)異常通知中定義多個(gè)方法,在后續(xù)的源碼分析中我們會(huì)發(fā)現(xiàn),這些方法最終會(huì)被注冊(cè)成對(duì)應(yīng)的異常的handler,像下面這樣

          public?static?class?CombinedThrowsAdvice?implements?ThrowsAdvice?{

          ????public?void?afterThrowing(RemoteException?ex)?throws?Throwable?{
          ????????//?Do?something?with?remote?exception
          ????}

          ????public?void?afterThrowing(Method?m,?Object[]?args,?Object?target,?ServletException?ex)?{
          ????????//?Do?something?with?all?arguments
          ????}
          }

          引入通知(Introduction Advice)

          引入通知的主要作用是可以讓生成的代理類實(shí)現(xiàn)額外的接口。例如在上面的例子中,我們?yōu)?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">DmzService創(chuàng)建一個(gè)代理對(duì)象,同時(shí)為其定義了一個(gè)引入通知

          public?class?DmzIntroductionAdvice?extends?DelegatingIntroductionInterceptor?implements?Runnable?{
          ?@Override
          ?public?void?run()?{
          ??System.out.println("running!!!!");
          ?}
          }

          在這個(gè)引入通知中,我們?yōu)槠湟肓艘粋€(gè)新的需要實(shí)現(xiàn)的接口Runnable,同時(shí)通知本身作為這個(gè)接口的實(shí)現(xiàn)類。

          通過這個(gè)引入通知,我們可以將生成的代理類強(qiáng)轉(zhuǎn)成Runnable類型然后執(zhí)行其run方法,同時(shí),run方法也會(huì)被前面定義的前置通知,后置通知等攔截。

          為了更好的了解引入通知,我們來需要了解下DelegatingIntroductionInterceptor這個(gè)類。見名知意,這個(gè)類就是一個(gè)委托引入攔截器,因?yàn)槲覀円獮榇眍愐胄碌慕涌冢驗(yàn)橹覀円峁┚唧w的實(shí)現(xiàn)的邏輯,而具體的實(shí)現(xiàn)的邏輯就可以被委托給這個(gè)DelegatingIntroductionInterceptor

          我們可以看看它的源碼

          public?class?DelegatingIntroductionInterceptor?extends?IntroductionInfoSupport
          ??implements?IntroductionInterceptor?
          {
          ?
          ????//?實(shí)際實(shí)現(xiàn)了引入邏輯的類
          ?@Nullable
          ?private?Object?delegate;
          ?
          ????//?對(duì)外提供了一個(gè)帶參的構(gòu)造函數(shù),通過這個(gè)構(gòu)造函數(shù)我們可以傳入一個(gè)
          ????//?具體的實(shí)現(xiàn)類
          ?public?DelegatingIntroductionInterceptor(Object?delegate)?{
          ??init(delegate);
          ?}
          ????//?對(duì)子類暴露了一個(gè)空參的構(gòu)造函數(shù),默認(rèn)將自身作為實(shí)現(xiàn)了引入邏輯的委托類
          ????//?我們上面的例子中就是使用的這種方法
          ?protected?DelegatingIntroductionInterceptor()?{
          ??init(this);
          ?}
          ?
          ????//?對(duì)這個(gè)類進(jìn)行初始化,要通過實(shí)際的實(shí)現(xiàn)類來找到具體要實(shí)現(xiàn)的接口
          ?private?void?init(Object?delegate)?{
          ??Assert.notNull(delegate,?"Delegate?must?not?be?null");
          ??this.delegate?=?delegate;
          ????????
          ????????//?找到delegate所有實(shí)現(xiàn)的接口
          ??implementInterfacesOnObject(delegate);
          ??
          ????????//?因?yàn)槲覀兛赡軙?huì)將DelegatingIntroductionInterceptor本身作為委托者
          ????????//?Spring的設(shè)計(jì)就是不對(duì)外暴露這兩個(gè)接口
          ????????//?如果將其暴露,意味著我們可以將代理類強(qiáng)轉(zhuǎn)成這種類型
          ??suppressInterface(IntroductionInterceptor.class);
          ??suppressInterface(DynamicIntroductionAdvice.class);
          ?}

          ?//?引入通知本身也是基于攔截器實(shí)現(xiàn)的,當(dāng)執(zhí)行一個(gè)方法時(shí)需要判斷這個(gè)方法
          ????//?是不是被引入的接口中定義的方法,如果是的話,那么不能調(diào)用目標(biāo)類的方法
          ????//?而要調(diào)用委托類的方法
          ?public?Object?invoke(MethodInvocation?mi)?throws?Throwable?{
          ??if?(isMethodOnIntroducedInterface(mi))?{
          ???Object?retVal?=?AopUtils.invokeJoinpointUsingReflection(this.delegate,?mi.getMethod(),?mi.getArguments());
          ???//?這里是處理一種特殊情況,方法的返回值是this的時(shí)候
          ????????????//?這里應(yīng)該返回代理類
          ???if?(retVal?==?this.delegate?&&?mi?instanceof?ProxyMethodInvocation)?{
          ????Object?proxy?=?((ProxyMethodInvocation)?mi).getProxy();
          ????if?(mi.getMethod().getReturnType().isInstance(proxy))?{
          ?????retVal?=?proxy;
          ????}
          ???}
          ????????????//?其余情況下直接將委托類的執(zhí)行結(jié)果返回
          ???return?retVal;
          ??}
          ????????//?執(zhí)行到這里說明不是引入的方法,這是Spring提供了一個(gè)擴(kuò)展邏輯
          ????????//?正常來說這個(gè)類只會(huì)處理引入的邏輯,通過這個(gè)方法可以對(duì)目標(biāo)類中的方法做攔截
          ????????//?不常用
          ??return?doProceed(mi);
          ?}

          ?protected?Object?doProceed(MethodInvocation?mi)?throws?Throwable?{
          ??return?mi.proceed();
          ?}

          }

          通過查看這個(gè)類的源碼我們可以發(fā)現(xiàn),所謂的引入其實(shí)就是在方法執(zhí)行的時(shí)候加了一層攔截,當(dāng)判斷這個(gè)方法是被引入的接口提供的方法的時(shí)候,那么就執(zhí)行委托類中的邏輯而不是目標(biāo)類中的方法

          關(guān)于通知的總結(jié)

          通過上文的分析我們可以發(fā)現(xiàn),通知總共可以分為這么幾類

          1. 普通的通知(前置,后置,異常等,沒有實(shí)現(xiàn)MethodInterceptor接口)
          2. 環(huán)繞通知(實(shí)現(xiàn)了MethodInterceptor接口)
          3. 引入通知(需要提供額外的引入的信息,實(shí)現(xiàn)了MethodInterceptor接口)

          上面的分類并不標(biāo)準(zhǔn),只是為了方便大家記憶跟理解,雖然我們普通的通知沒有直接實(shí)現(xiàn)MethodInterceptor接口,但其實(shí)它的底層也是依賴于攔截器來完成的,大家可以看看下面這個(gè)類

          class?MethodBeforeAdviceAdapter?implements?AdvisorAdapter,?Serializable?{

          ?@Override
          ?public?boolean?supportsAdvice(Advice?advice)?{
          ??return?(advice?instanceof?MethodBeforeAdvice);
          ?}
          ?
          ????//?根據(jù)傳入的一個(gè)前置通知,創(chuàng)建一個(gè)對(duì)應(yīng)的攔截器
          ?@Override
          ?public?MethodInterceptor?getInterceptor(Advisor?advisor)?{
          ??MethodBeforeAdvice?advice?=?(MethodBeforeAdvice)?advisor.getAdvice();
          ??return?new?MethodBeforeAdviceInterceptor(advice);
          ?}

          }

          public?class?MethodBeforeAdviceInterceptor?implements?MethodInterceptor,?BeforeAdvice,?Serializable?{

          ?private?final?MethodBeforeAdvice?advice;

          ?public?MethodBeforeAdviceInterceptor(MethodBeforeAdvice?advice)?{
          ??Assert.notNull(advice,?"Advice?must?not?be?null");
          ??this.advice?=?advice;
          ?}

          ?//?實(shí)際上還是利用攔截器,在方法執(zhí)行前調(diào)用了通知的before方法完成了前置通知
          ?@Override
          ?public?Object?invoke(MethodInvocation?mi)?throws?Throwable?{
          ??this.advice.before(mi.getMethod(),?mi.getArguments(),?mi.getThis());
          ??return?mi.proceed();
          ?}

          }

          Advisor (綁定通知跟切點(diǎn))

          一個(gè)Advisor實(shí)際上就是一個(gè)綁定在指定切點(diǎn)上的通知。在前面的例子我們可以發(fā)現(xiàn),有兩種添加通知的方式

          //?一個(gè)Advisor代表的是一個(gè)已經(jīng)跟指定切點(diǎn)綁定了的通知
          //?在這個(gè)例子中意味著環(huán)繞通知不會(huì)作用到toString方法上
          Advisor?advisor?=?new?DefaultPointcutAdvisor(new?DmzPointcut(),?new?DmzAroundAdvice());

          //?添加一個(gè)綁定了指定切點(diǎn)的環(huán)繞通知
          proxyFactory.addAdvisor(advisor);

          //?添加一個(gè)返回后的通知
          proxyFactory.addAdvice(new?DmzAfterReturnAdvice());

          一種是直接添加了一個(gè)Advisor,還有一種是添加一個(gè)Advice,后者也會(huì)被轉(zhuǎn)換成一個(gè)Advisor然后再進(jìn)行添加,沒有指定切點(diǎn)的通知是沒有任何意義的

          public?void?addAdvice(Advice?advice)?throws?AopConfigException?{
          ????int?pos?=?this.advisors.size();
          ????//?默認(rèn)添加到集合的最后一個(gè)位置
          ????addAdvice(pos,?advice);
          }

          //?這個(gè)方法添加通知
          public?void?addAdvice(int?pos,?Advice?advice)?throws?AopConfigException?{
          ????Assert.notNull(advice,?"Advice?must?not?be?null");
          ????
          ????//?如果是一個(gè)引入通知,那么構(gòu)建一個(gè)DefaultIntroductionAdvisor
          ????//?DefaultIntroductionAdvisor會(huì)匹配所有類
          ????if?(advice?instanceof?IntroductionInfo)?{
          ????????addAdvisor(pos,?new?DefaultIntroductionAdvisor(advice,?(IntroductionInfo)?advice));
          ????}
          ????//?不能直接添加一個(gè)不是IntroductionInfo的DynamicIntroductionAdvice(動(dòng)態(tài)引入通知)
          ????else?if?(advice?instanceof?DynamicIntroductionAdvice)?{
          ????????throw?new?AopConfigException("DynamicIntroductionAdvice?may?only?be?added?as?part?of?IntroductionAdvisor");
          ????}
          ????else?{
          ????????//?如果是普通的通知,那么會(huì)創(chuàng)建一個(gè)DefaultPointcutAdvisor
          ????????//?DefaultPointcutAdvisor所定義的切點(diǎn)會(huì)匹配所有類以及所有方法
          ????????addAdvisor(pos,?new?DefaultPointcutAdvisor(advice));
          ????}
          }

          ProxyCreatorSupport

          這個(gè)類的主要作用是為創(chuàng)建一個(gè)AOP代理對(duì)象提供一些功能支持,通過它的getAopProxyFactory能獲取一個(gè)創(chuàng)建代理對(duì)象的工廠。

          //?這里我只保留了這個(gè)類中的關(guān)鍵代碼
          public?class?ProxyCreatorSupport?extends?AdvisedSupport?{?

          ????private?AopProxyFactory?aopProxyFactory;

          ????//?空參構(gòu)造,默認(rèn)會(huì)創(chuàng)建一個(gè)DefaultAopProxyFactory
          ????//?通過這個(gè)ProxyFactory可以創(chuàng)建一個(gè)cglib代理或者jdk代理
          ????public?ProxyCreatorSupport()?{
          ????????this.aopProxyFactory?=?new?DefaultAopProxyFactory();
          ????}

          ????//?通過這個(gè)方法可以創(chuàng)建一個(gè)具體的代理對(duì)象
          ????protected?final?synchronized?AopProxy?createAopProxy()?{
          ????????if?(!this.active)?{
          ????????????activate();
          ????????}
          ????????//?實(shí)際就是使用DefaultAopProxyFactory來創(chuàng)建一個(gè)代理對(duì)象
          ????????//?可以看到在調(diào)用createAopProxy方法時(shí),傳入的參數(shù)是this
          ????????//?這是因?yàn)镻roxyCreatorSupport本身就保存了創(chuàng)建整個(gè)代理對(duì)象所需要的配置信息
          ????????return?getAopProxyFactory().createAopProxy(this);
          ????}
          }
          image-20200701231849588

          另外通過上面的UML類圖還能看到,ProxyCreatorSupport繼承了AdvisedSupportAdvisedSupport繼承了ProxyConfig

          ProxyConfig

          其中ProxyConfig是所有的AOP代理工廠的父類,它包含了創(chuàng)建一個(gè)AOP代理所需要的基礎(chǔ)的通用的一些配置信息

          //?這里省略了一些getter跟setter方法
          public?class?ProxyConfig?implements?Serializable?{
          ?
          ????//?是否開啟cglib代理,默認(rèn)不開啟使用jdk動(dòng)態(tài)代理
          ?private?boolean?proxyTargetClass?=?false;

          ????//?是否啟用優(yōu)化,默認(rèn)為false,按照官網(wǎng)對(duì)這個(gè)參數(shù)的解釋
          ????//?這個(gè)優(yōu)化是針對(duì)cglib,如果設(shè)計(jì)為true的話,會(huì)做一些侵入性的優(yōu)化
          ????//?是否開啟在jdk代理的情況下沒有影響
          ????//?官網(wǎng)中特地說明了,除非對(duì)cglib的優(yōu)化非常了解,否則不要開啟這個(gè)參數(shù)
          ?private?boolean?optimize?=?false;
          ?
          ????//?生成的代理類是否需要實(shí)現(xiàn)Advised接口,這個(gè)接口可以向外提供操作通知的方法
          ????//?如果為false會(huì)實(shí)現(xiàn)
          ????//?為true的話,不會(huì)實(shí)現(xiàn)
          ?boolean?opaque?=?false;
          ?
          ????//?是否將當(dāng)前的配置類暴露到一個(gè)線程上下文中,如果設(shè)置為true的話
          ????//?可以通過AopContext.currentProxy()來獲取到當(dāng)前的代理對(duì)象
          ?boolean?exposeProxy?=?false;
          ????
          ????//?標(biāo)志著是否凍結(jié)整個(gè)配置,如果凍結(jié)了,那么配置信息將不允許修改
          ?private?boolean?frozen?=?false;
          }

          AdvisedSupport

          當(dāng)我們?yōu)槟硞€(gè)對(duì)象創(chuàng)建代理時(shí),除了需要上面的ProxyConfig提供的一些基礎(chǔ)配置外,起碼還需要知道

          1. 需要執(zhí)行的通知是哪些?
          2. 目標(biāo)對(duì)象是誰?
          3. 創(chuàng)建出來的代理需要實(shí)現(xiàn)哪些接口?

          而這些配置信息是由AdvisedSupport提供的,AdvisedSupport本身實(shí)現(xiàn)了Advised接口,Advised接口定義了管理通知的方法。


          在了解了上面的API后我們來看看Spring提供了幾種創(chuàng)建AOP代理的方式

          1. ProxyFactoryBean
          2. ProxyFactory
          3. Auto-proxy

          ProxyFactoryBean的方式創(chuàng)建AOP代理

          使用示例


          <beans?xmlns="http://www.springframework.org/schema/beans"
          ????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          ????xsi:schemaLocation="http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans.xsd">


          ?<bean?class="com.dmz.spring.initalize.service.DmzService"?name="dmzService"/>

          ?<bean?id="aroundAdvice"?class="com.dmz.spring.initalize.aop.advice.DmzAroundAdvice"/>

          ?<bean?id="dmzProxy"
          ????class="org.springframework.aop.framework.ProxyFactoryBean">

          ????????
          ??<property?name="proxyInterfaces"?value="java.lang.Runnable"/>
          ??<property?name="proxyTargetClass"?value="true"/>
          ???<property?name="target"?ref="dmzService"/>
          ??<property?name="interceptorNames">
          ???<list>
          ????<value>aroundAdvicevalue>
          ???list>
          ??property>
          ?bean>

          beans>
          //?目標(biāo)類
          public?class?DmzService?{
          ?@Override
          ?public?String?toString()?{
          ??System.out.println("dmzService?toString?invoke");
          ??return?"dmzService";
          ?}

          ?public?void?testAop(){
          ??System.out.println("testAop?invoke");
          ?}
          }

          //?通知
          public?class?DmzAroundAdvice?implements?MethodInterceptor?{
          ?@Override
          ?public?Object?invoke(MethodInvocation?invocation)?throws?Throwable?{
          ??System.out.println("aroundAdvice?invoked");
          ??return?invocation.proceed();
          ?}
          }

          public?class?SourceMain?{
          ?public?static?void?main(String[]?args)?{
          ??ClassPathXmlApplicationContext?cc?=
          ????new?ClassPathXmlApplicationContext("application-init.xml");
          ??DmzService?dmzProxy?=?((DmzService)?cc.getBean("dmzProxy"));
          ??dmzProxy.testAop();
          ?}
          }

          ProxyFactoryBean介紹

          跟普通的FactoryBean一樣,這個(gè)類的主要作用就是通過getObject方法能夠獲取一個(gè)Bean,不同的是這個(gè)類獲取到的是代理后的Bean。

          我們查看這個(gè)類的繼承關(guān)系可以發(fā)現(xiàn)

          image-20200701181049929

          這個(gè)類除了實(shí)現(xiàn)了FactoryBean接口以及一些Aware接口外,額外還繼承了ProxyCreatorSupport類。它是一個(gè)factoryBean,所以我們重點(diǎn)就關(guān)注它的getObject方法即可。

          public?Object?getObject()?throws?BeansException?{
          ????//?初始化通知鏈
          ????//?這里主要就是將在XML中配置的通知添加到
          ????//?AdvisedSupport管理的配置中去
          ????initializeAdvisorChain();
          ????if?(isSingleton())?{
          ????????//?如果是單例的,那么獲取一個(gè)單例的代理對(duì)象
          ????????return?getSingletonInstance();
          ????}
          ????else?{
          ????????if?(this.targetName?==?null)?{
          ????????????logger.warn("Using?non-singleton?proxies?with?singleton?targets?is?often?undesirable.?"?+
          ????????????????????????"Enable?prototype?proxies?by?setting?the?'targetName'?property.");
          ????????}
          ????????//?如果是原型的,獲取一個(gè)原型的代理對(duì)象
          ????????return?newPrototypeInstance();
          ????}
          }

          關(guān)于這段代碼就不做過多分析了,它其實(shí)就兩步(不管是哪種方式創(chuàng)建代理,都分為這兩步)

          1. 完善創(chuàng)建代理需要的配置信息
          2. 創(chuàng)建代理

          其中配置信息分為兩部分,其一是AppConfig管理的通用的配置信息,其二是AdvisedSupport管理的通知信息。通用的配置信息我們可以直接在XML中配置,例如在上面的例子中我們就配置了proxyTargetClass屬性,而通知信息即使我們?cè)赬ML中配置了也還需要做一層轉(zhuǎn)換,在前面我們也提到過了,所有的Advice都會(huì)被轉(zhuǎn)換成Advisor添加到配置信息中。

          ProxyFactory的方式創(chuàng)建AOP代理

          使用示例(略,見開頭)

          ProxyFactory介紹

          image-20200702084419039

          從上面我們可以看出,ProxyFactory也繼承自ProxyCreatorSupport,從之前的例子我們也能感受到,使用它的API來創(chuàng)建一個(gè)代理對(duì)象也是要先去設(shè)置相關(guān)的配置信息,最后再調(diào)用創(chuàng)建代理的方法

          我們之后要分析的自動(dòng)代理內(nèi)部就是通過創(chuàng)建了一個(gè)ProxyFactory來獲取代理對(duì)象的。

          我們可以對(duì)比下ProxyFactoryBeanProxyFactory在創(chuàng)建代理對(duì)象時(shí)的代碼

          • ProxyFactory
          public?Object?getProxy()?{
          ????//?調(diào)用了ProxyCreatorSupport的createAopProxy()方法創(chuàng)建一個(gè)AopProxy對(duì)象
          ????//?然后調(diào)用AopProxy對(duì)象的getProxy方法
          ????return?createAopProxy().getProxy();
          }
          • ProxyFactoryBean
          private?synchronized?Object?getSingletonInstance()?{
          ????if?(this.singletonInstance?==?null)?{
          ????????this.targetSource?=?freshTargetSource();
          ????????if?(this.autodetectInterfaces?&&?getProxiedInterfaces().length?==?0?&&?!isProxyTargetClass())?{
          ????????????Class?targetClass?=?getTargetClass();
          ????????????if?(targetClass?==?null)?{
          ????????????????throw?new?FactoryBeanNotInitializedException("Cannot?determine?target?class?for?proxy");
          ????????????}
          ????????????setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass,?this.proxyClassLoader));
          ????????}
          ????????super.setFrozen(this.freezeProxy);
          ????????//?重點(diǎn)就看這里
          ????????//?這里調(diào)用了ProxyCreatorSupport的createAopProxy()方法創(chuàng)建一個(gè)AopProxy對(duì)象
          ????????//?而getProxy方法就是調(diào)用創(chuàng)建的AopProxy的getProxy方法
          ????????this.singletonInstance?=?getProxy(createAopProxy());
          ????}
          ????return?this.singletonInstance;
          }

          protected?Object?getProxy(AopProxy?aopProxy)?{
          ????return?aopProxy.getProxy(this.proxyClassLoader);
          }

          綜上,我們可以得出結(jié)論,不管是通過哪種方式創(chuàng)建AOP代理,核心代碼就一句

          createAopProxy().getProxy()

          這句代碼也是我們接下來源碼分析的重點(diǎn)

          Auto-proxy(實(shí)現(xiàn)自動(dòng)AOP代理)

          自動(dòng)代理機(jī)制的實(shí)現(xiàn)其實(shí)很簡(jiǎn)單,就是通過Bean的后置處理器,在創(chuàng)建Bean的最后一步對(duì)Bean進(jìn)行代理,并將代理對(duì)象放入到容器中。

          實(shí)現(xiàn)自動(dòng)代理的核心類就是AbstractAutoProxyCreator。我們來看看它的繼承關(guān)系

          image-20200702103750263

          為了更好的體會(huì)自動(dòng)代理的作用,我們對(duì)它的三個(gè)具體的實(shí)現(xiàn)類來進(jìn)行分析,分別是

          1. BeanNameAutoProxyCreator
          2. DefaultAdvisorAutoProxyCreator
          3. AnnotationAwareAspectJAutoProxyCreator

          BeanNameAutoProxyCreator

          使用示例


          <beans?xmlns="http://www.springframework.org/schema/beans"
          ????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          ????xsi:schemaLocation="http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans.xsd">


          ?<bean?class="com.dmz.spring.initalize.service.DmzService"?name="dmzService"/>

          ?<bean?id="aroundAdvice"?class="com.dmz.spring.initalize.aop.advice.DmzAroundAdvice"/>

          ?<bean?id="beforeAdvice"?class="com.dmz.spring.initalize.aop.advice.DmzBeforeAdvice"/>

          ????
          ?<bean?class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"?name="autoProxyCreator">
          ????????
          ??<property?name="proxyTargetClass"?value="true"/>
          ?????????
          ??<property?name="beanNames"?value="dmz*"/>
          ????????
          ??<property?name="interceptorNames">
          ???<list>
          ????<value>beforeAdvicevalue>
          ????<value>aroundAdvicevalue>
          ???list>
          ??property>
          ?bean>

          beans>
          public?class?SourceMain?{
          ?public?static?void?main(String[]?args)?{
          ??ClassPathXmlApplicationContext?cc?=
          ????new?ClassPathXmlApplicationContext("application-init.xml");
          ??DmzService?dmzProxy?=?((DmzService)?cc.getBean("dmzService"));
          ??dmzProxy.testAop();
          ?}
          }
          //?程序打印:
          //?before?invoke?method?[testAop],aop?before?logic?invoked
          //?aroundAdvice?invoked
          //?testAop?invoke

          DefaultAdvisorAutoProxyCreator

          使用示例

          在上面例子的基礎(chǔ)上我們要修改配置文件,如下:


          <beans?xmlns="http://www.springframework.org/schema/beans"
          ????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          ????xsi:schemaLocation="http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans.xsd">


          ?<bean?class="com.dmz.spring.initalize.service.DmzService"?name="dmzService"/>

          ?<bean?id="aroundAdvice"?class="com.dmz.spring.initalize.aop.advice.DmzAroundAdvice"/>

          ?<bean?id="beforeAdvice"?class="com.dmz.spring.initalize.aop.advice.DmzBeforeAdvice"/>
          ?
          ?<bean?class="org.springframework.aop.support.DefaultPointcutAdvisor"?id="dmzBeforeAdvisor">
          ??<property?name="advice"?ref="beforeAdvice"/>
          ?bean>

          ?<bean?class="org.springframework.aop.support.DefaultPointcutAdvisor"?id="dmzAroundAdvisor">
          ??<property?name="advice"?ref="aroundAdvice"/>
          ?bean>

          ?<bean?class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          ????id="advisorAutoProxyCreator">

          ????????
          ??<property?name="usePrefix"?value="true"/>
          ??<property?name="advisorBeanNamePrefix"?value="dmz"/>
          ??
          ????????<property?name="proxyTargetClass"?value="true"/>
          ?bean>
          beans>

          測(cè)試代碼就不放了,大家可以自行測(cè)試,肯定是沒問題的

          AnnotationAwareAspectJAutoProxyCreator

          我們正常在使用AOP的時(shí)候都會(huì)在配置類上添加一個(gè)@EnableAspectJAutoProxy注解,這個(gè)注解干了什么事呢?

          實(shí)際就是向容器中注冊(cè)了一個(gè)AnnotationAwareAspectJAutoProxyCreator

          @Target(ElementType.TYPE)
          @Retention(RetentionPolicy.RUNTIME)
          @Documented
          //?這里導(dǎo)入了一個(gè)類
          @Import(AspectJAutoProxyRegistrar.class)
          public?@interface?EnableAspectJAutoProxy?{
          ?
          ?boolean?proxyTargetClass()?default?false;

          ?boolean?exposeProxy()?default?false;

          }

          通過@EnableAspectJAutoProxy導(dǎo)入了一個(gè)AspectJAutoProxyRegistrar,這個(gè)類會(huì)向容器中注冊(cè)一個(gè)AnnotationAwareAspectJAutoProxyCreator,對(duì)應(yīng)源碼如下:

          class?AspectJAutoProxyRegistrar?implements?ImportBeanDefinitionRegistrar?{
          ?@Override
          ?public?void?registerBeanDefinitions(
          ???AnnotationMetadata?importingClassMetadata,?BeanDefinitionRegistry?registry)
          ?
          {
          ??
          ????????//?在這里完成的注冊(cè)
          ??//?最終會(huì)調(diào)用到AopUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法
          ????????//?完成AnnotationAwareAspectJAutoProxyCreator這個(gè)bd的注冊(cè)
          ??AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
          ??
          ????????//?解析注解的屬性
          ????????// proxyTargetClass:為true的話開啟cglib代理,默認(rèn)為jdk代理
          ????????// exposeProxy:是否將代理對(duì)象暴露到線程上下文中
          ??AnnotationAttributes?enableAspectJAutoProxy?=
          ????AnnotationConfigUtils.attributesFor(importingClassMetadata,?EnableAspectJAutoProxy.class);
          ??if?(enableAspectJAutoProxy?!=?null)?{
          ???if?(enableAspectJAutoProxy.getBoolean("proxyTargetClass"))?{
          ????AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
          ???}
          ??????????
          ???if?(enableAspectJAutoProxy.getBoolean("exposeProxy"))?{
          ????AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
          ???}
          ??}
          ?}

          }

          前面已經(jīng)說過了,自動(dòng)代理機(jī)制實(shí)際上就是Spring在內(nèi)部new了一個(gè)ProxyFactory,通過它創(chuàng)建了一個(gè)代理對(duì)象。對(duì)應(yīng)的代碼就在AbstractAutoProxyCreator中的createProxy方法內(nèi),源碼如下:

          protected?Object?createProxy(Class?beanClass,?@Nullable?String?beanName,
          ?????????????????????????????@Nullable?Object[]?specificInterceptors,?TargetSource?targetSource)
          ?
          {

          ????if?(this.beanFactory?instanceof?ConfigurableListableBeanFactory)?{
          ????????AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)?this.beanFactory,?beanName,?beanClass);
          ????}
          ?//?看到了吧,這里創(chuàng)建了一個(gè)proxyFactory
          ????ProxyFactory?proxyFactory?=?new?ProxyFactory();
          ????proxyFactory.copyFrom(this);

          ????if?(!proxyFactory.isProxyTargetClass())?{
          ????????if?(shouldProxyTargetClass(beanClass,?beanName))?{
          ????????????proxyFactory.setProxyTargetClass(true);
          ????????}
          ????????else?{
          ????????????evaluateProxyInterfaces(beanClass,?proxyFactory);
          ????????}
          ????}

          ????Advisor[]?advisors?=?buildAdvisors(beanName,?specificInterceptors);
          ????proxyFactory.addAdvisors(advisors);
          ????proxyFactory.setTargetSource(targetSource);
          ????customizeProxyFactory(proxyFactory);

          ????proxyFactory.setFrozen(this.freezeProxy);
          ????if?(advisorsPreFiltered())?{
          ????????proxyFactory.setPreFiltered(true);
          ????}
          ?//?通過proxyFactory來創(chuàng)建一個(gè)代理對(duì)象
          ????return?proxyFactory.getProxy(getProxyClassLoader());
          }

          關(guān)于這個(gè)類的執(zhí)行流程在下篇文章中我再詳細(xì)介紹,接下來我們要分析的就是具體創(chuàng)建AOP代理的源碼了。對(duì)應(yīng)的核心源碼就是我們之前所提到的

          createAopProxy().getProxy();

          這行代碼分為兩步,我們逐步分析

          1. 調(diào)用AopProxyFactorycreateAopProxy()方法獲取一個(gè)AopProxy對(duì)象
          2. 調(diào)用AopProxy對(duì)象的getProxy()方法

          核心源碼分析

          createAopProxy方法分析

          AopProxyFactory在Spring中只有一個(gè)默認(rèn)的實(shí)現(xiàn)類,就是DefaultAopProxyFactory,它的對(duì)應(yīng)的createAopProxy的是實(shí)現(xiàn)代碼如下:

          public?class?DefaultAopProxyFactory?implements?AopProxyFactory,?Serializable?{
          ?
          ????//?就是通過AOP相關(guān)的配置信息來決定到底是使用cglib代理還是jdk代理
          ????@Override
          ????public?AopProxy?createAopProxy(AdvisedSupport?config)?throws?AopConfigException?{
          ????????//?如果開啟了優(yōu)化,或者ProxyTargetClass設(shè)置為true
          ????????//?或者沒有提供代理類需要實(shí)現(xiàn)的接口,那么使用cglib代理
          ????????//?在前面分析參數(shù)的時(shí)候已經(jīng)說過了
          ????????//?默認(rèn)情況下Optimize都為false,也不建議設(shè)置為true,因?yàn)闀?huì)進(jìn)行一些侵入性的優(yōu)化
          ????????//?除非你對(duì)cglib的優(yōu)化非常了解,否則不建議開啟
          ????????if?(config.isOptimize()?||?config.isProxyTargetClass()?||?hasNoUserSuppliedProxyInterfaces(config))?{
          ????????????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.");
          ????????????}
          ????????????//?需要注意的是,如果需要代理的類本身就是一個(gè)接口
          ????????????//?或者需要被代理的類本身就是一個(gè)通過jdk動(dòng)態(tài)代理生成的類
          ????????????//?那么不管如何設(shè)置都會(huì)使用jdk動(dòng)態(tài)代理
          ????????????if?(targetClass.isInterface()?||?Proxy.isProxyClass(targetClass))?{
          ????????????????return?new?JdkDynamicAopProxy(config);
          ????????????}
          ????????????return?new?ObjenesisCglibAopProxy(config);
          ????????}
          ????????//?否則都是jdk代理
          ????????else?{
          ????????????return?new?JdkDynamicAopProxy(config);
          ????????}
          ????}

          ?//?判斷是否提供代理類需要實(shí)現(xiàn)的接口
          ????private?boolean?hasNoUserSuppliedProxyInterfaces(AdvisedSupport?config)?{
          ????????Class[]?ifcs?=?config.getProxiedInterfaces();
          ????????return?(ifcs.length?==?0?||?(ifcs.length?==?1?&&?SpringProxy.class.isAssignableFrom(ifcs[0])));
          ????}

          }

          getProxy方法分析

          從對(duì)createAopProxy方法的分析可以看到,我們要么執(zhí)行的是ObjenesisCglibAopProxy中的getProxy方法,要么就是JdkDynamicAopProxygetProxy方法,二者的區(qū)別在于一個(gè)是通過cglib的方式生成代理對(duì)象,而后者則是通過jdk的方式生成動(dòng)態(tài)代理。

          這里我只分析一個(gè)JdkDynamicAopProxy,首先我們來看看這個(gè)類的繼承關(guān)系

          ?

          希望你之前已經(jīng)閱讀過

          原創(chuàng) 動(dòng)態(tài)代理學(xué)習(xí)(一)自己動(dòng)手模擬JDK動(dòng)態(tài)代理

          原創(chuàng) 動(dòng)態(tài)代理學(xué)習(xí)(二)JDK動(dòng)態(tài)代理源碼分析

          image-20200702154037428

          可以看到這個(gè)類本身就是一個(gè)InvocationHandler,這意味著當(dāng)調(diào)用代理對(duì)象中的方法時(shí),最終會(huì)調(diào)用到JdkDynamicAopProxyinvoke方法。

          所以對(duì)于這個(gè)類我們起碼應(yīng)該關(guān)注兩個(gè)方法

          1. getProxy方法
          2. invoke方法

          getProxy方法源碼如下:

          public?Object?getProxy(@Nullable?ClassLoader?classLoader)?{
          ????if?(logger.isDebugEnabled())?{
          ????????logger.debug("Creating?JDK?dynamic?proxy:?target?source?is?"?+?this.advised.getTargetSource());
          ????}
          ????//?這里獲取到代理類需要實(shí)現(xiàn)的所有的接口
          ????Class[]?proxiedInterfaces?=?AopProxyUtils.completeProxiedInterfaces(this.advised,?true);
          ????//?需要明確是否在接口定義了hashCode以及equals方法
          ????//?如果接口中沒有定義,那么在調(diào)用代理對(duì)象的equals方法的時(shí)候
          ????//?如果兩個(gè)對(duì)象相等,那么意味著它們的目標(biāo)對(duì)象,通知以及實(shí)現(xiàn)的接口都相同
          ????findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
          ????return?Proxy.newProxyInstance(classLoader,?proxiedInterfaces,?this);
          }

          我們?cè)賮砜纯吹降资窃趺传@取到需要實(shí)現(xiàn)的接口的

          static?Class[]?completeProxiedInterfaces(AdvisedSupport?advised,?boolean?decoratingProxy)?{
          ????//?第一步:獲取在配置中指定的需要實(shí)現(xiàn)的接口
          ????Class[]?specifiedInterfaces?=?advised.getProxiedInterfaces();
          ????
          ????//?第二步:如果沒有指定需要實(shí)現(xiàn)的接口,但是需要代理的目標(biāo)類本身就是一個(gè)接口
          ????//?那么將其添加到代理類需要實(shí)現(xiàn)的接口的集合中
          ????//?如果目標(biāo)類本身不是一個(gè)接口,但是是經(jīng)過jdk代理后的一個(gè)類
          ????//?那么獲取這個(gè)代理后的類所有實(shí)現(xiàn)的接口,并添加到需要實(shí)現(xiàn)的接口集合中
          ????if?(specifiedInterfaces.length?==?0)?{
          ????????Class?targetClass?=?advised.getTargetClass();
          ????????if?(targetClass?!=?null)?{
          ????????????if?(targetClass.isInterface())?{
          ????????????????advised.setInterfaces(targetClass);
          ????????????}
          ????????????else?if?(Proxy.isProxyClass(targetClass))?{
          ????????????????advised.setInterfaces(targetClass.getInterfaces());
          ????????????}
          ????????????specifiedInterfaces?=?advised.getProxiedInterfaces();
          ????????}
          ????}
          ????
          ????//?第三步:為代理類添加三個(gè)默認(rèn)需要實(shí)現(xiàn)的接口,分別是
          ????//?1.SpringProxy,一個(gè)標(biāo)記接口,代表這個(gè)類是通過Spring的AOP代理生成的
          ????//?2.Advised,提供了管理通知的方法
          ????//?3.DecoratingProxy,用戶獲取到真實(shí)的目標(biāo)對(duì)象
          ????//?這個(gè)真實(shí)對(duì)象指的是在嵌套代理的情況下會(huì)獲取到最終的目標(biāo)對(duì)象
          ????//?而不是指返回這個(gè)ProxyFactory的target
          ????boolean?addSpringProxy?=?!advised.isInterfaceProxied(SpringProxy.class);
          ????boolean?addAdvised?=?!advised.isOpaque()?&&?!advised.isInterfaceProxied(Advised.class);
          ????boolean?addDecoratingProxy?=?(decoratingProxy?&&?!advised.isInterfaceProxied(DecoratingProxy.class));
          ????int?nonUserIfcCount?=?0;
          ????if?(addSpringProxy)?{
          ????????nonUserIfcCount++;
          ????}
          ????if?(addAdvised)?{
          ????????nonUserIfcCount++;
          ????}
          ????if?(addDecoratingProxy)?{
          ????????nonUserIfcCount++;
          ????}
          ????Class[]?proxiedInterfaces?=?new?Class[specifiedInterfaces.length?+?nonUserIfcCount];
          ????System.arraycopy(specifiedInterfaces,?0,?proxiedInterfaces,?0,?specifiedInterfaces.length);
          ????int?index?=?specifiedInterfaces.length;
          ????if?(addSpringProxy)?{
          ????????proxiedInterfaces[index]?=?SpringProxy.class;
          ????????index++;
          ????}
          ????if?(addAdvised)?{
          ????????proxiedInterfaces[index]?=?Advised.class;
          ????????index++;
          ????}
          ????if?(addDecoratingProxy)?{
          ????????proxiedInterfaces[index]?=?DecoratingProxy.class;
          ????}
          ????return?proxiedInterfaces;
          }

          invoke方法分析

          在確認(rèn)了需要實(shí)現(xiàn)的接口后,直接調(diào)用了jdk的動(dòng)態(tài)代理方法,這個(gè)我們就不做分析了,接下來我們來看看Spring是如何將通知應(yīng)用到代理對(duì)象上的,對(duì)應(yīng)的要分析的代碼就是JdkDynamicAopProxyinvoke方法,源碼如下:

          //?這個(gè)方法的代碼稍微有點(diǎn)長(zhǎng),代碼也比較難,希望大家能耐心看完
          public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{
          ????Object?oldProxy?=?null;
          ????boolean?setProxyContext?=?false;

          ????TargetSource?targetSource?=?this.advised.targetSource;
          ????Object?target?=?null;

          ????try?{
          ????????//?首先處理的是hashCode跟equals方法
          ????????//?如果接口中沒有定義這兩個(gè)方法,那么會(huì)調(diào)用本類中定義的equals方法
          ????????//?前面我們也說過了,只有當(dāng)兩個(gè)類的目標(biāo)對(duì)象,通知以及實(shí)現(xiàn)的接口都相等的情況下
          ????????//?equals才會(huì)返回true
          ????????//?如果接口中定義了這兩個(gè)方法,那么最終會(huì)調(diào)用目標(biāo)對(duì)象中的方法
          ????????if?(!this.equalsDefined?&&?AopUtils.isEqualsMethod(method))?{
          ????????????return?equals(args[0]);
          ????????}
          ????????else?if?(!this.hashCodeDefined?&&?AopUtils.isHashCodeMethod(method))?{
          ????????????return?hashCode();
          ????????}
          ????????
          ????????//?也就是說我們調(diào)用的是DecoratingProxy這個(gè)接口中的方法
          ????????//?這個(gè)接口中只定義了一個(gè)getDecoratedClass方法,用于獲取到
          ????????//?最終的目標(biāo)對(duì)象,在方法實(shí)現(xiàn)中會(huì)通過一個(gè)while循環(huán)來不斷接近
          ????????//?最終的目標(biāo)對(duì)象,直到得到的目標(biāo)對(duì)象不是一個(gè)被代理的對(duì)象才會(huì)返回
          ????????else?if?(method.getDeclaringClass()?==?DecoratingProxy.class)?{
          ????????????return?AopProxyUtils.ultimateTargetClass(this.advised);
          ????????}
          ????????
          ????????//?說明調(diào)用的是Advised接口中的方法,這里只是單純的進(jìn)行反射調(diào)用
          ????????else?if?(!this.advised.opaque?&&?method.getDeclaringClass().isInterface()?&&
          ?????????????????method.getDeclaringClass().isAssignableFrom(Advised.class))?{

          ????????????return?AopUtils.invokeJoinpointUsingReflection(this.advised,?method,?args);
          ????????}

          ????????Object?retVal;
          ??
          ????????//?說明需要將代理類暴露到線程上下文中
          ????????//?調(diào)用AopContext.setCurrentProxy方法將其放入到一個(gè)threadLocal中
          ????????if?(this.advised.exposeProxy)?{
          ????????????oldProxy?=?AopContext.setCurrentProxy(proxy);
          ????????????setProxyContext?=?true;
          ????????}
          ??
          ????????//?接下來就是真正的執(zhí)行代理邏輯了
          ????????target?=?targetSource.getTarget();
          ????????Class?targetClass?=?(target?!=?null???target.getClass()?:?null);
          ??
          ????????//?先獲取整個(gè)攔截器鏈
          ????????List?chain?=?this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,?targetClass);
          ????????
          ????????//?如果沒有進(jìn)行攔截,直接反射調(diào)用方法
          ????????if?(chain.isEmpty())?{
          ????????????Object[]?argsToUse?=?AopProxyUtils.adaptArgumentsIfNecessary(method,?args);
          ????????????retVal?=?AopUtils.invokeJoinpointUsingReflection(target,?method,?argsToUse);
          ????????}
          ????????
          ????????//?否則開始執(zhí)行整個(gè)鏈條
          ????????else?{
          ????????????MethodInvocation?invocation?=
          ????????????????new?ReflectiveMethodInvocation(proxy,?target,?method,?args,?targetClass,?chain);
          ????????????retVal?=?invocation.proceed();
          ????????}
          ?
          ????????//?這里是處理一種特殊情況,就是當(dāng)執(zhí)行的方法返回值為this的情況
          ????????//?這種情況下,需要返回當(dāng)前的代理對(duì)象而不是目標(biāo)對(duì)象
          ????????Class?returnType?=?method.getReturnType();
          ????????if?(retVal?!=?null?&&?retVal?==?target?&&
          ????????????returnType?!=?Object.class?&&?returnType.isInstance(proxy)?&&
          ????????????!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass()))?{
          ????????????retVal?=?proxy;
          ????????}
          ????????else?if?(retVal?==?null?&&?returnType?!=?Void.TYPE?&&?returnType.isPrimitive())?{
          ????????????throw?new?AopInvocationException(
          ????????????????"Null?return?value?from?advice?does?not?match?primitive?return?type?for:?"?+?method);
          ????????}
          ????????return?retVal;
          ????}
          ????finally?{
          ????????if?(target?!=?null?&&?!targetSource.isStatic())?{
          ????????????targetSource.releaseTarget(target);
          ????????}
          ????????if?(setProxyContext)?{
          ????????????AopContext.setCurrentProxy(oldProxy);
          ????????}
          ????}
          }

          在上面整個(gè)流程中,我們抓住核心的兩步

          1. 獲取整個(gè)攔截器鏈
          2. 開始在攔截器鏈上執(zhí)行方法

          我們先看第一步,對(duì)應(yīng)源碼如下:

          public?List?getInterceptorsAndDynamicInterceptionAdvice(Method?method,?@Nullable?Class?targetClass)?{
          ????MethodCacheKey?cacheKey?=?new?MethodCacheKey(method);
          ????List?cached?=?this.methodCache.get(cacheKey);
          ????if?(cached?==?null)?{
          ????????//?調(diào)用了advisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice方法
          ????????cached?=?this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
          ????????????this,?method,?targetClass);
          ????????this.methodCache.put(cacheKey,?cached);
          ????}
          ????return?cached;
          }
          public?List?getInterceptorsAndDynamicInterceptionAdvice(
          ????Advised?config,?Method?method,?@Nullable?Class?targetClass)
          ?{

          ????List?interceptorList?=?new?ArrayList(config.getAdvisors().length);

          ????Class?actualClass?=?(targetClass?!=?null???targetClass?:?method.getDeclaringClass());

          ????//?是否有引入通知
          ????boolean?hasIntroductions?=?hasMatchingIntroductions(config,?actualClass);

          ????AdvisorAdapterRegistry?registry?=?GlobalAdvisorAdapterRegistry.getInstance();

          ????//?獲取到所有的通知
          ????for?(Advisor?advisor?:?config.getAdvisors())?{
          ????????//?除了引入通知外,可以認(rèn)為所有的通知都是一個(gè)PointcutAdvisor
          ????????if?(advisor?instanceof?PointcutAdvisor)?{
          ????????????PointcutAdvisor?pointcutAdvisor?=?(PointcutAdvisor)?advisor;
          ????????????// config.isPreFiltered:代表的是配置已經(jīng)過濾好了,是可以直接應(yīng)用的
          ????????????//?這句代碼的含義就是配置是預(yù)過濾的或者在類級(jí)別上是匹配的
          ????????????if?(config.isPreFiltered()?||?pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass))?{
          ????????????????//?接下來要判斷在方法級(jí)別上是否匹配
          ????????????????MethodMatcher?mm?=?pointcutAdvisor.getPointcut().getMethodMatcher();
          ????????????????if?(MethodMatchers.matches(mm,?method,?actualClass,?hasIntroductions))?{
          ????????????????????//?將通知轉(zhuǎn)換成對(duì)應(yīng)的攔截器
          ????????????????????//?有些通知本身就是攔截器,例如環(huán)繞通知
          ????????????????????//?有些通知需要通過一個(gè)AdvisorAdapter來適配成對(duì)應(yīng)的攔截器
          ????????????????????//?例如前置通知,后置通知,異常通知等
          ????????????????????//?其中MethodBeforeAdvice會(huì)被適配成MethodBeforeAdviceInterceptor
          ????????????????????//?AfterReturningAdvice會(huì)被適配成AfterReturningAdviceInterceptor
          ????????????????????//?ThrowAdvice會(huì)被適配成ThrowsAdviceInterceptor
          ????????????????????MethodInterceptor[]?interceptors?=?registry.getInterceptors(advisor);

          ????????????????????//?如果是動(dòng)態(tài)的攔截,會(huì)創(chuàng)建一個(gè)InterceptorAndDynamicMethodMatcher
          ????????????????????//?動(dòng)態(tài)的攔截意味著需要根據(jù)具體的參數(shù)來決定是否進(jìn)行攔截
          ????????????????????if?(mm.isRuntime())?{
          ????????????????????????for?(MethodInterceptor?interceptor?:?interceptors)?{
          ????????????????????????????interceptorList.add(new?InterceptorAndDynamicMethodMatcher(interceptor,?mm));
          ????????????????????????}
          ????????????????????}
          ????????????????????else?{
          ????????????????????????interceptorList.addAll(Arrays.asList(interceptors));
          ????????????????????}
          ????????????????}
          ????????????}
          ????????}
          ????????else?if?(advisor?instanceof?IntroductionAdvisor)?{
          ????????????//?說明是引入通知
          ????????????IntroductionAdvisor?ia?=?(IntroductionAdvisor)?advisor;
          ????????????if?(config.isPreFiltered()?||?ia.getClassFilter().matches(actualClass))?{
          ????????????????//?前文我們有提到過,引入通知實(shí)際就是通過一個(gè)攔截器
          ????????????????//?將方法交由引入的類執(zhí)行而不是目標(biāo)類
          ????????????????Interceptor[]?interceptors?=?registry.getInterceptors(advisor);
          ????????????????interceptorList.addAll(Arrays.asList(interceptors));
          ????????????}
          ????????}
          ????????else?{
          ????????????//?可能會(huì)擴(kuò)展出一些通知,一般不會(huì)
          ????????????Interceptor[]?interceptors?=?registry.getInterceptors(advisor);
          ????????????interceptorList.addAll(Arrays.asList(interceptors));
          ????????}
          ????}

          ????return?interceptorList;
          }

          在構(gòu)建好攔截器鏈后,接下來就是真正執(zhí)行方法了,對(duì)應(yīng)代碼就是

          //?先創(chuàng)建一個(gè)MethodInvocation
          MethodInvocation?invocation?=
          ????new?ReflectiveMethodInvocation(proxy,?target,?method,?args,?targetClass,?chain);
          //?開始在攔截器鏈上執(zhí)行這個(gè)方法
          retVal?=?invocation.proceed();

          最后的關(guān)鍵代碼就落在了ReflectiveMethodInvocationproceed方法

          public?Object?proceed()?throws?Throwable?{
          ?
          ????//?滿足這個(gè)條件,說明執(zhí)行到了最后一個(gè)攔截器,那么直接反射調(diào)用目標(biāo)方法
          ???if?(this.currentInterceptorIndex?==?this.interceptorsAndDynamicMethodMatchers.size()?-?1)?{
          ??????return?invokeJoinpoint();
          ???}
          ?
          ????//?獲取到下一個(gè)要執(zhí)行的攔截器
          ???Object?interceptorOrInterceptionAdvice?=
          ?????????this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
          ???if?(interceptorOrInterceptionAdvice?instanceof?InterceptorAndDynamicMethodMatcher)?{
          ??????//?前面構(gòu)建攔截器鏈的時(shí)候我們可以看到,動(dòng)態(tài)的攔截的話會(huì)創(chuàng)建一個(gè)InterceptorAndDynamicMethodMatcher
          ??????InterceptorAndDynamicMethodMatcher?dm?=
          ????????????(InterceptorAndDynamicMethodMatcher)?interceptorOrInterceptionAdvice;
          ??????if?(dm.methodMatcher.matches(this.method,?this.targetClass,?this.arguments))?{
          ?????????return?dm.interceptor.invoke(this);
          ??????}
          ??????else?{
          ????????//?如果匹配失敗了,執(zhí)行攔截器鏈中的下一個(gè)攔截邏輯
          ?????????return?proceed();
          ??????}
          ???}
          ???else?{
          ???//?調(diào)用攔截器中的invoke方法,可以看到這里將this作為參數(shù)傳入了
          ??????//?所以我們?cè)跀r截器中調(diào)用?MethodInvocation的proceed時(shí)又會(huì)進(jìn)行入當(dāng)前這個(gè)方法
          ??????//?然后去執(zhí)行鏈條中的下一個(gè)攔截器?
          ??????return?((MethodInterceptor)?interceptorOrInterceptionAdvice).invoke(this);
          ???}
          }

          總結(jié)

          本文主要是為下篇文章做準(zhǔn)備,下篇文章將會(huì)結(jié)束整個(gè)IOC流程的分析,IOC的最后一步便是為Bean創(chuàng)建代理。本文已經(jīng)分析了代理的具體創(chuàng)建邏輯,在下篇文章中我們主要結(jié)合Spring的啟動(dòng)流程來看一看Spring是如何將通知添加到創(chuàng)建代理的配置信息中去的。

          關(guān)于整個(gè)IOC跟AOP的模塊還會(huì)有兩篇文章,一篇用于結(jié)束整個(gè)IOC流程,另外一篇專門探討Spring中循環(huán)依賴的解決。完成這兩篇文章中,接下來打算用5到7篇文章對(duì)Spring的事務(wù)管理進(jìn)行分析!

          如果我的文章能幫到你,記得點(diǎn)個(gè)贊哈~!

          我叫DMZ,一個(gè)在學(xué)習(xí)路上匍匐前行的小菜鳥!

          瀏覽 55
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    我要毛片毛片毛片毛片毛 | www.一级片 | 海量毛片 | 日韩国产欧美 | 欧美A∨在线 |