<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,快來瞧一瞧看一看撒!

          共 65353字,需瀏覽 131分鐘

           ·

          2021-04-25 10:10

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”

          優(yōu)質(zhì)文章,第一時間送達(dá)

            作者 |  狐言不胡言

          來源 |  urlify.cn/zyUNfi

          76套java從入門到精通實(shí)戰(zhàn)課程分享



          AOP分析

          AOP是什么

          Aspect Oriented Programming 面向切面編程,在不改變類的代碼的情況下,對類的方法進(jìn)行功能增強(qiáng)

          那么如果要實(shí)現(xiàn)一個AOP,需要做的事情就是要向使用的用戶提供AOP功能,能夠通過AOP技術(shù)實(shí)現(xiàn)對類的方法進(jìn)行功能增強(qiáng)

          AOP中的元素

          • Advice 通知,即增強(qiáng)的功能

          • Join points 連接點(diǎn),可以選擇的方法點(diǎn),即有哪些可以增強(qiáng)的方法供選擇

          • Pointcut 切入點(diǎn),選擇切入的方法點(diǎn),即對哪些方法進(jìn)行增強(qiáng)

          • Aspact 切面,選擇的多個方法點(diǎn) + 增強(qiáng)的功能,即Advice和Pointcut的組合

          • Introduction 引入,添加新的方法、屬性到已經(jīng)存在的類中,叫做引入

          • Weaving 織入,即不改變原來的代碼,加入增強(qiáng)的功能

          手寫AOP的話,上面幾個元素有的是需要用戶提供的:Advice、Pointcut、Aspact,用戶需要提供增強(qiáng)的功能和切入點(diǎn)、切面信息;AOP框架需要提供Join points、Weaving

          AOP提供的功能

          • 需要功能的增強(qiáng),即Advice通知

          • 對類的方法進(jìn)行增強(qiáng),那需要可以選擇的要增強(qiáng)的方法點(diǎn),即Pointcut切入點(diǎn)

          • 需要在不改變原類代碼的情況下,進(jìn)行功能的增強(qiáng),即Weaving織入

          圖解AOP

          假設(shè)我們現(xiàn)在玩一局王者榮耀,選擇了一個英雄魯班,這個魯班需要參與整個游戲直到結(jié)束,不管是否掛機(jī);剛剛開始的時候,沒有任何裝備,假設(shè)魯班身上的各個部位是Join points,即這些部位需要裝備去增強(qiáng)它,那每一個裝備就是Advice增強(qiáng)的功能,比如增加攻速、生命等,現(xiàn)在買了一個鞋子,那么就是選擇在速度上進(jìn)行增強(qiáng),即穿在腳上,那么就是Pointcut,那么這個鞋子加上腳就是Aspact切面,上面說的例子可能不夠好,見諒?。?/span>

          特點(diǎn)分析

          1. Advice

          實(shí)現(xiàn)一個Advice,就需要知道Advice有哪些特點(diǎn),從上面可以知道Advice是用戶來提供的,所以有很多不可控的因素

          • 用戶性:由用戶來提供增強(qiáng)的功能,即增強(qiáng)功能的代碼是用戶來進(jìn)行編寫的

          • 多變性:既然用戶來提供,那么對于不同的需求,增強(qiáng)的邏輯都是不一樣的

          • 可選時機(jī):用戶可以選擇在方法的前面、后面、異常時進(jìn)行功能增強(qiáng)

          • 多重性:同一個切入點(diǎn),即同一個方法,可以有多重的增強(qiáng),不止增強(qiáng)一次

          1. Pointcut

          切入點(diǎn),通過上面知道它也是用戶提供的,所以它的特點(diǎn)和Advice基本上差不多

          • 用戶性:由用戶來指定,對哪些方法進(jìn)行功能增強(qiáng)

          • 多變性:用戶可以靈活的來指定

          • 多點(diǎn)性:用戶可以選擇在多個方法點(diǎn)上進(jìn)行功能增強(qiáng)

          1. Weaving

          織入,這部分代碼,是需要框架提供的,即是需要我們自己去實(shí)現(xiàn)的邏輯,通過這個可以把增強(qiáng)的功能加入到用戶指定的方法上面

          • 無侵入性:不改變原來類的代碼,去實(shí)現(xiàn)功能的增強(qiáng)

          • 需要我們在AOP框架中自己實(shí)現(xiàn)邏輯

          通過上面的內(nèi)容,可以知道,需要做的事情就是Advice、Pointcut、Weaving三個部分,Join points為什么不需要去實(shí)現(xiàn)呢,這部分內(nèi)容在編寫代碼的過程中就可以知道了

          Advice實(shí)現(xiàn)

          Advice是由用戶來實(shí)現(xiàn)的,這部分邏輯需要用戶寫好然后我們實(shí)現(xiàn)AOP的時候來進(jìn)行使用;我們需要認(rèn)識用戶的東西,用戶需要使用我們寫的框架,而且還需要隔絕用戶的多變性

          那么需要做的事情是啥呢,可以定義一個標(biāo)準(zhǔn)的接口,用戶通過實(shí)現(xiàn)接口來提供不同的增強(qiáng)邏輯,這就是應(yīng)對變化的方式,面向接口編程

          定義Advice接口

          定義的Advice是一個頂級接口,不需要寫任何的方法,然后根據(jù)前置、后置、環(huán)繞、異常增強(qiáng),來去實(shí)現(xiàn)Advice接口,那么這些增強(qiáng)需要的參數(shù)是一樣的嗎,請往下看

          Advice接口:

          /**
           * @className: Advice
           * @description: 通知的標(biāo)準(zhǔn)接口
           * @author TR
           */
          public interface Advice {

          }

          首先,我們知道,增強(qiáng)是對方法進(jìn)行增強(qiáng),那么使用Advice的時候,需要給的就是方法的一些信息

          1. 前置增強(qiáng)

          在方法執(zhí)行前進(jìn)行增強(qiáng),那么可以知道前置增強(qiáng)是不需要返回值的,需要的參數(shù)如下:

          • 方法自身 Method

          • 方法的參數(shù) Object[]

          • 方法所在的類(對象) Object

          1. 后置增強(qiáng)

          在方法執(zhí)行后進(jìn)行增強(qiáng),那需要的參數(shù)是不是需要增加一個啊,即需要方法的返回值,因?yàn)槲胰绻枰獙Ψ祷刂底鲆幌绿幚?,就需要用到它,而且后置增?qiáng)也是不需要返回值的,需要的參數(shù)如下:

          • 方法自身 Method

          • 方法的參數(shù) Object[]

          • 方法所在的類(對象) Object

          • 方法的返回值 Object

          1. 環(huán)繞增強(qiáng)

          包裹方法進(jìn)行增強(qiáng),它是需要包裹整個方法,即方法由它來執(zhí)行,那么環(huán)繞增強(qiáng)是需要返回值的,這個返回值是需要增強(qiáng)方法的返回值,需要的參數(shù)如下:

          • 方法自身 Method

          • 方法的參數(shù) Object[]

          • 方法所在的類(對象) Object

          1. 異常增強(qiáng)

          捕獲方法執(zhí)行時的異常信息,然后進(jìn)行增強(qiáng),而且它也是需要包裹方法進(jìn)行增強(qiáng)的,即它可以在環(huán)繞增強(qiáng)中來實(shí)現(xiàn)

          通過上面知道,需要定義三個方法:前置增強(qiáng)的方法、后置增強(qiáng)的方法、環(huán)繞和異常增強(qiáng)的方法,那這三個方法是定義在一個接口里面,還是分三個接口呢,根據(jù)單一職責(zé)原則,還是分三個接口來實(shí)現(xiàn)比較好,而且還可以根據(jù)不同的接口類型來區(qū)分是哪個Advice

          定義前置、后置、環(huán)繞和異常增強(qiáng)接口

          定義前置增強(qiáng)接口MethodBeforeAdvice:

          /**
           * @className: MethodBeforeAdvice
           * @description: 前置增強(qiáng)接口
           * @author TR
           */
          public interface MethodBeforeAdvice extends Advice {

              /**
               * 前置增強(qiáng)方法
               * @param method: 將要被執(zhí)行的方法
               * @param target: 執(zhí)行方法的目標(biāo)對象
               * @param args: 執(zhí)行方法的參數(shù)
               * @return: void
               **/
              void before(Method method, Object target, Object[] args);
          }

          定義后置增強(qiáng)接口AfterReturningAdvice:

          /**
           * @className: AfterReturningAdvice
           * @description: 后置增強(qiáng)接口
           * @author TR
           */
          public interface AfterReturningAdvice extends Advice {
              
              /**
               * 后置增強(qiáng)方法
               * @param method: 將要被執(zhí)行的方法
               * @param target: 執(zhí)行方法的目標(biāo)對象
               * @param args: 執(zhí)行方法的參數(shù)
               * @param returnValue: 執(zhí)行方法的返回值
               * @return: void
               **/
              void after(Method method, Object target, Object[] args, Object returnValue);
          }

          定義環(huán)繞、異常增強(qiáng)接口MethodInterceptor:

          /**
           * @className: MethodInterceptor
           * @description: 環(huán)繞、異常增強(qiáng)接口
           * @author TR
           */
          public interface MethodInterceptor extends Advice {

              /**
               * 環(huán)繞、異常增強(qiáng)方法,在方法實(shí)現(xiàn)中需要調(diào)用目標(biāo)方法
               * @param method: 將要被執(zhí)行的方法
               * @param target: 執(zhí)行方法的目標(biāo)對象
               * @param args: 執(zhí)行方法的參數(shù)
               * @return: java.lang.Object 執(zhí)行方法的返回值
               * @throws Throwable
               **/
              Object invoke(Method method, Object target, Object[] args) throws Throwable;
          }

          類圖如下:

          Pointcut實(shí)現(xiàn)

          Pointcut的特點(diǎn):

          • 用戶性:由用戶來指定,對哪些方法進(jìn)行功能增強(qiáng)

          • 多變性:用戶可以靈活的來指定

          • 多點(diǎn)性:用戶可以選擇在多個方法點(diǎn)上進(jìn)行功能增強(qiáng)

          我們需要給用戶提供一個東西,讓用戶可以靈活的來指定方法點(diǎn),而且我們獲取到的時候又能夠知道,用戶對哪些方法點(diǎn)進(jìn)行了指定

          指定對哪些方法進(jìn)行增強(qiáng),指定的信息是什么,其實(shí)就是一個或者多個方法,而且如果有重載存在呢,所以這個指定的東西,就是一個完整的方法簽名

          那該怎么做到靈活性、多點(diǎn)性呢,這個指定的信息是可以描述一類方法的,比如:

          • 某個包下某個類的某個方法

          • 某個包下某個類的所有方法

          • 某個包下所有類中以get開頭的方法

          • 某個包下所有類中以get開頭以sevice結(jié)尾的方法

          • 某個包下及其子包下所有類中以get開頭以sevice結(jié)尾的方法

          那么可以定義一個表達(dá)式,來去描述上面的信息,這個描述的信息是包名.類名.方法名(參數(shù)類型)

          每一部分是如何要求的呢?

          • 包名:需要有父子特點(diǎn),可以模糊匹配

          • 類名:可以模糊匹配

          • 方法名:可以模糊匹配

          • 參數(shù)類型:可以有多個

          定義的表達(dá)式是需要來判斷:是否需要對某個類的某個方法進(jìn)行增強(qiáng),那么需要去匹配類和匹配方法

          匹配的表達(dá)式:

          • 正則表達(dá)式

          • AspactJ表達(dá)式

          AspactJ表達(dá)式學(xué)習(xí)

          /**
           * @className: AspectJTest
           * @description: AspectJ測試類
           */
          public class AspectJTest {

              public static void main(String[] args) throws NoSuchMethodException {
                  //獲得切點(diǎn)解析器
                  PointcutParser pp = PointcutParser
                          .getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
                  //切點(diǎn)解析器根據(jù)規(guī)則,解析出一個類型匹配器
                  TypePatternMatcher tp = pp.parseTypePattern("di.*");
                  //根據(jù)表達(dá)式生成一個切點(diǎn)表達(dá)式
                  PointcutExpression pe = pp.parsePointcutExpression("execution(* demo.beans.BeanFactory.get*(..))");

                  //匹配MagicGril的getName方法
                  Class<?> cl =  MagicGril.class;
                  Method method = cl.getMethod("getName", null);
                  //匹配方法執(zhí)行
                  ShadowMatch sm = pe.matchesMethodExecution(method);
                  System.out.println("是否匹配到方法:" + sm.alwaysMatches());
                  System.out.println(cl.getName() + ",是否匹配表達(dá)式:" + pe.couldMatchJoinPointsInType(cl));
                  System.out.println(DefaultBeanFactory.class + ",是否匹配表達(dá)式:" + pe.couldMatchJoinPointsInType(DefaultBeanFactory.class));

                  System.out.println(cl.getName() +"類下的所有方法:");
                  for (Method method1 : cl.getMethods()) {
                      System.out.println(method1.getName());
                  }
              }
          }

          輸出結(jié)果:

          通過上面的描述,可以知道,切點(diǎn)該怎么去設(shè)計了

          切點(diǎn)需要有的屬性就是切點(diǎn)表達(dá)式,需要提供的功能就是匹配類和匹配方法

          而且這里也可以像Advice一樣定義一個頂級接口,因?yàn)槿绻院笥衅渌谋磉_(dá)式更加好用的話,需要擴(kuò)展,那么只需要繼承定義的這個頂級接口就行了,不管它內(nèi)部如何實(shí)現(xiàn),都要去實(shí)現(xiàn)我們定義的匹配類和匹配方法的行為

          定義PointCut接口

          /**
           * @className: PointCut
           * @description: 切點(diǎn)匹配接口
           * @author: TR
           */
          public interface PointCut {

              /**
               * 匹配類
               * @author: jinpeng.sun
               * @date: 2021/4/19 13:46
               * @param targetClass: 匹配的目標(biāo)類
               * @return: boolean
               **/
               boolean matchClass(Class<?> targetClass);

               /**
                * 匹配方法
                * @author: jinpeng.sun
                * @date: 2021/4/19 13:46
                * @param method: 匹配的目標(biāo)方法
                * @param targetClass: 匹配的目標(biāo)類
                * @return: boolean
                **/
               boolean matchMethod(Method method, Class<?> targetClass);
          }

          定義正則表達(dá)式的實(shí)現(xiàn)類:RegExpressionPointcut

          此處不實(shí)現(xiàn),主要使用AspactJ的方式

          /**
           * @className: RegExpressionPointcut
           * @description: 正則表達(dá)式實(shí)現(xiàn)類
           * @author: TR
           */
          public class RegExpressionPointcut implements PointCut {

              @Override
              public boolean matchClass(Class<?> targetClass) {
                  return false;
              }

              @Override
              public boolean matchMethod(Method method, Class<?> targetClass) {
                  return false;
              }
          }

          定義AspectJ切點(diǎn)表達(dá)式的實(shí)現(xiàn)類:AspectJExpressionPointcut

          /**
           * @className: AspectJExpressionPointcut
           * @description: AspectJ切點(diǎn)表達(dá)式實(shí)現(xiàn)類
           * @author: TR
           */
          public class AspectJExpressionPointcut implements PointCut {

              /** 獲得切點(diǎn)解析器 */
              PointcutParser pp = PointcutParser
                      .getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();

              /** 切點(diǎn)表達(dá)式的字符串形式 */
              private String expression;

              /** AspectJ中的切點(diǎn)表達(dá)式 */
              private PointcutExpression pe;

              public AspectJExpressionPointcut(String expression) {
                  super();
                  this.expression = expression;
                  pe = pp.parsePointcutExpression(expression);
              }


              @Override
              public boolean matchClass(Class<?> targetClass) {
                  return pe.couldMatchJoinPointsInType(targetClass);
              }

              @Override
              public boolean matchMethod(Method method, Class<?> targetClass) {
                  ShadowMatch sm = pe.matchesMethodExecution(method);
                  return sm.alwaysMatches();
              }

              public String getExpression() {
                  return expression;
              }
          }

          實(shí)現(xiàn)步驟:

          1. maven引入Aspectj的jar

           <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjweaver</artifactId>
              <version>1.9.6</version>
           </dependency>
          1. 獲得切點(diǎn)解析器

           PointcutParser pp = PointcutParser
                  .getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
          1. 解析切點(diǎn)表達(dá)式,獲得PointcutExpression

          PointcutExpression pe = pp.parsePointcutExpression(
              "execution(* edu.dongnao.courseware.beans.BeanFactory.get*(..))");
          1. 使用PointcutExpression匹配類,不可靠

          pe.couldMatchJoinPointsInType(targetClass)
          1. 使用PointcutExpression匹配方法,可靠

          ShadowMatch sm = pe.matchesMethodExecution(method);
          return sm.alwaysMatches();

          類圖如下:

          Aspact實(shí)現(xiàn)

          上面實(shí)現(xiàn)了Advice和Pointcut,那么用戶該如何使用呢?

          Advice是用戶提供的功能增強(qiáng)實(shí)現(xiàn),是需要繼承接口的,那么可以把Advice配置成一個bean,Pointcut是切點(diǎn)表達(dá)式,是用來匹配類和方法的,是不需要配置成bean的,只需要提供一個字符串形式的表達(dá)式就行了,那么adviceBeanName+expression就組成了切面

          下面通過外觀模式來實(shí)現(xiàn)切面,把Advice和Pointcut組合起來

          定義Advisor接口

          /**
           * @className: Advisor
           * @description: 構(gòu)建切面的接口,組合advice和pointcut
           * @author: TR
           */
          public interface Advisor {

              /**
               * 獲取通知bean的名稱
               * @return: java.lang.String
               **/
              String getAdviceBeanName();

              /**
               * 獲取切點(diǎn)表達(dá)式
               * @return: java.lang.String
               **/
              String getExpression();
          }

          定義PointcutAdvisor接口

          /**
           * @className: PointcutAdvisor
           * @description: 切點(diǎn)通知者,繼承自Advisor,擴(kuò)展了pointcut
           * @author: TR
           */
          public interface PointcutAdvisor extends Advisor {

              /**
               * 獲取切點(diǎn)
               * @return: PointCut
               **/
              PointCut getPointCut();
          }

          定義AspectJPointcutAdvisor實(shí)現(xiàn)類

          /**
           * @className: AspectJPointcutAdvisor
           * @description: AspectJ切點(diǎn)表達(dá)式的通知者實(shí)現(xiàn)類
           * @author: TR
           */
          public class AspectJPointcutAdvisor implements PointcutAdvisor {

              /** 通知bean的名稱 */
              private String adviceBeanName;

              /** 表達(dá)式 */
              private String expression;

              /** 切點(diǎn) */
              private PointCut pointCut;

              public AspectJPointcutAdvisor(String adviceBeanName, String expression) {
                  this.adviceBeanName = adviceBeanName;
                  this.expression = expression;
                  this.pointCut = new AspectJExpressionPointcut(expression);
              }

              @Override
              public PointCut getPointCut() {
                  return pointCut;
              }

              @Override
              public String getAdviceBeanName() {
                  return adviceBeanName;
              }

              @Override
              public String getExpression() {
                  return expression;
              }
          }

          下面的類不予實(shí)現(xiàn),主要使用AspactJ的形式

          /**
           * @className: RegPointcutAdvisor
           * @description: 正則切點(diǎn)表達(dá)式的通知者實(shí)現(xiàn)類
           * @author: TR
           */
          public class RegPointcutAdvisor implements PointcutAdvisor {

              /** 通知bean的名稱 */
              private String adviceBeanName;

              /** 表達(dá)式 */
              private String expression;

              /** 切點(diǎn) */
              private PointCut pointCut;

              public RegPointcutAdvisor(String adviceBeanName, String expression) {
                  this.adviceBeanName = adviceBeanName;
                  this.expression = expression;
                  this.pointCut = new RegExpressionPointcut();
              }

              @Override
              public PointCut getPointCut() {
                  return null;
              }

              @Override
              public String getAdviceBeanName() {
                  return null;
              }

              @Override
              public String getExpression() {
                  return null;
              }
          }

          類圖如下:

          從上面的圖中看到了,如果再擴(kuò)展其他的切點(diǎn)表達(dá)式,那么在實(shí)現(xiàn)類中,可以看到,有很多的重復(fù)代碼,那么是不是還可以優(yōu)化一下呢,可以在實(shí)現(xiàn)類的上層再加一個抽象類,來繼承PointcutAdvisor,然后主要的切點(diǎn)實(shí)現(xiàn)繼承這個抽象類就行了

          Weaving實(shí)現(xiàn)

          要完成的事情

          將用戶提供的增強(qiáng)功能加入到指定的方法上,需要我們來實(shí)現(xiàn)

          什么時候做織入

          在創(chuàng)建Bean實(shí)例的時候,在Bean初始化完成后,再進(jìn)行織入

          怎么知道Bean要進(jìn)行增強(qiáng)

          需要遍歷Bean類及其所有的方法,然后依次的去匹配用戶指定的切面,如果存在匹配的切面,就是需要增強(qiáng)了

          怎么織入呢,就是需要用到代理了!

          用戶需要去注冊切面,我們還需要實(shí)現(xiàn)判斷匹配、織入的的邏輯,這部分代碼改如何寫,需要寫到哪里呢

          現(xiàn)在要做的事情,就是在Bean創(chuàng)建的過程中加一項(xiàng)處理,后面可能會在Bean的創(chuàng)建過程中加入更多的處理,如果這部分代碼都寫在BeanFactory中,那么這個類是不是就會有特別多的代碼,而且后面不方便擴(kuò)展

          看下Bean的創(chuàng)建過程:

          上面圖中,每個箭頭都是加的擴(kuò)展點(diǎn),后面可能存在的是,需要在這些點(diǎn)上加入更多的處理邏輯,那么就需要設(shè)計一種方式,在不改變BeanFactory的情況下,能靈活的擴(kuò)展,那么可以使用觀察者模式,有幾個擴(kuò)展點(diǎn),就是有幾個主題,六個觀察者

          定義觀察者接口BeanPostProcessor

          /**
           * @className: BeanPostProcessor
           * @description: 后置處理器,Bean實(shí)例化完成后及依賴注入完成后觸發(fā)
           * @author: TR
           */
          public interface BeanPostProcessor {

              /**
               * bean初始化前的處理
               * @author: TR
               * @param bean: bean實(shí)例
               * @param beanName: bean名稱
               * @return: java.lang.Object
               **/
              default Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
                 return bean;
              }

              /**
               * bean初始化后的處理
               * @author: TR
               * @param bean: bean實(shí)例
               * @param beanName: bean名稱
               * @return: java.lang.Object
               **/
              default Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
                  return bean;
              }
          }

          定義通知接口Aware

          **
           * @className: Aware
           * @description: 構(gòu)建通知接口
           * @date: 2021/4/19 16:38
           * @author: jinpeng.sun
           */
          public interface Aware {
          }
          /**
           * @className: BeanFactoryAware
           * @description: bean工廠構(gòu)建通知接口
           * @author: TR
           */
          public interface BeanFactoryAware extends Aware {

              /**
               * 接口實(shí)現(xiàn)者獲得bean工廠方法
               * @author: TR
               * @param bf:
               * @return: void
               **/
              void setBeanFactory(BeanFactory bf);
          }

          上面的接口主要用來獲得Bean工廠信息

          定義通知者注冊接口AdvisorRegistry

          這個接口主要用來把Advisor注冊到增強(qiáng)功能的實(shí)現(xiàn)類里面

          /**
           * @className: AdvisorRegistry
           * @description: 通知者注冊接口
           * @author: TR
           */
          public interface AdvisorRegistry {

              /**
               * 注冊通知者
               * @author: TR
               * @param advisor:
               * @return: void
               **/
              public void registerAdvisor(Advisor advisor);

              /**
               * 獲得通知者列表
               * @author: TR
               * @date: 2021/4/19 16:45
               *
               * @return: java.util.List<demo.aop.advisor.Advisor>
               **/
              public List<Advisor> getAdvisors();
          }

          定義增強(qiáng)處理的觀察者實(shí)現(xiàn)類AdvisorAutoProxyCreator

          /**
           * @className: AdvisorAutoProxyCreator
           * @description: 功能增強(qiáng)的實(shí)現(xiàn)類,用戶和框架交互的核心類
           * 用戶通過Advisor提供切面,向DefaultBeanFactory注入該實(shí)現(xiàn)
           * 框架內(nèi)部:DefaultBeanFactory注入ioc容器
           * DefaultBeanFactory調(diào)用BeanPostProcessor接口相關(guān)方法,進(jìn)行功能增強(qiáng)
           * @author: TR
           */
          public class AdvisorAutoProxyCreator implements BeanPostProcessor, BeanFactoryAware, AdvisorRegistry {

              /** 通知者列表 */
              private List<Advisor> advisors;

              /** 當(dāng)前的bean */
              private BeanFactory beanFactory;

              public AdvisorAutoProxyCreator() {
                  this.advisors = new ArrayList<>();
              }

              @Override
              public void registerAdvisor(Advisor advisor) {
                  this.advisors.add(advisor);
              }

              @Override
              public List<Advisor> getAdvisors() {
                  return this.advisors;
              }

              @Override
              public void setBeanFactory(BeanFactory bf) {
                  this.beanFactory = bf;
              }

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

          注冊BeanPostProcessor

          BeanFactory接口中增加注冊BeanPostProcessor的方法

              /** 注冊BeanPostProcessor */
              void registerBeanPostProcessor(BeanPostProcessor beanPostProcessor);

          DefaultBeanFactory實(shí)現(xiàn)類中增加如下方法:

              private List<BeanPostProcessor> postProcessors = Collections.synchronizedList(new ArrayList<>());

              @Override
              public void registerBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
                  postProcessors.add(beanPostProcessor);
                  if (beanPostProcessor instanceof BeanFactoryAware) {
                      ((BeanFactoryAware) beanPostProcessor).setBeanFactory(this);
                  }
              }

          getBean方法中增加bean初始化前后的處理:

           @Override
              public Object getBean(String beanName) throws Exception {
                  //獲取bean定義
                  BeanDefinition bd = beanDefinitionMap.get(beanName);
                  Object bean = doGetBean(beanName);

                  //屬性注入
                  setPropertyDIValues(bd, bean);

                  //bean初始化前的處理
                  bean = this.applyPostProcessBeforeInitialization(bean, beanName);

                  //bean的生命周期
                  if (StringUtils.isNotBlank(bd.getInitMethodName())) {
                      doInitMethod(bean,bd);
                  }

                  //bean初始化后的處理
                  bean = this.applyPostProcessAfterInitialization(bean, beanName);

                  return bean;
              }
              
              /**
               * bean初始化后的處理
               * @author: TR 
               * @param bean: 
               * @param beanName: 
               * @return: java.lang.Object
               **/
              private Object applyPostProcessAfterInitialization(Object bean, String beanName) throws Exception {
                  for (BeanPostProcessor bp : this.postProcessors) {
                      bean = bp.postProcessBeforeInitialization(bean, beanName);
                  }
                  return bean;
              }

              /**
               * bean初始化前的處理
               * @author: TR 
               * @param bean: 
               * @param beanName: 
               * @return: java.lang.Object
               **/
              private Object applyPostProcessBeforeInitialization(Object bean, String beanName) throws Exception {
                  for (BeanPostProcessor bp : this.postProcessors) {
                      bean = bp.postProcessAfterInitialization(bean, beanName);
                  }
                  return bean;
              }

          下面需要實(shí)現(xiàn)的就是判斷bean是否需要增強(qiáng)了,那么需要獲取到bean的所有方法,然后根據(jù)注冊進(jìn)來的advisors去遍歷它,然后得到切點(diǎn)去匹配類和方法

          修改AdvisorAutoProxyCreator類中的postProcessAfterInitialization方法:

              @Override
              public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
                  //判斷是否需要進(jìn)行切面增強(qiáng),及獲得增強(qiáng)的通知實(shí)現(xiàn)
                  List<Advisor> advisors = getMatchedAdvisors(bean, beanName);
                  //如果需要增強(qiáng),返回增強(qiáng)后的對象
                  if (CollectionUtils.isNotEmpty(advisors)) {
                      //使用代理模式進(jìn)行功能增強(qiáng)
                  }
                  return bean;
              }

          下面是獲取匹配的方法代碼:

              /**
               * 獲取匹配的方法
               * @author: TR
               * @param bean: bean實(shí)例
               * @param beanName: bean名稱
               * @return: void
               **/
              private List<Advisor> getMatchedAdvisors(Object bean, String beanName) {
                  if (CollectionUtils.isEmpty(advisors)) {
                      return null;
                  }
                  //得到類
                  Class<?> beanClass = bean.getClass();
                  //得到所有的方法
                  List<Method> allMethods = getAllMethodForClass(beanClass);

                  //存放匹配的Advisor
                  List<Advisor> advisors = new ArrayList<>();
                  for (Advisor ad : this.advisors) {
                      if (ad instanceof PointcutAdvisor) {
                          //判斷是否匹配
                          if (isPointcutMatchBean((PointcutAdvisor) ad, beanClass, allMethods)) {
                              advisors.add(ad);
                          }
                      }
                  }
                  return advisors;
              }

          獲取所有的方法,使用的是Spring framework提供的工具類,來找到類下面所有的方法:

              /**
               * 獲取所有的方法
               * @author: TR
               * @param beanClass:
               * @return: void
               **/
              private List<Method> getAllMethodForClass(Class<?> beanClass) {
                  List<Method> allMethods = new LinkedList<>();
                  Set<Class<?>> classes = new LinkedHashSet<>(ClassUtils.getAllInterfacesForClassAsSet(beanClass));
                  classes.add(beanClass);
                  for (Class<?> cc : classes) {
                      //根據(jù)工具類獲取所有的方法
                      Method[] methods = ReflectionUtils.getAllDeclaredMethods(cc);
                      for (Method m : methods) {
                        allMethods.add(m);
                      }
                  }
                  return  allMethods;
              }

          下面是判斷是否有匹配切點(diǎn)規(guī)則的方法,使用PointCut中定義的方法來實(shí)現(xiàn):

             /**
               * 判斷是否有匹配切點(diǎn)規(guī)則的方法
               * @author: TR
               * @param ad: 切面
               * @param beanClass: 指定的類
               * @param allMethods: 指定的類下面所有的方法
               * @return: void
               **/
              private boolean isPointcutMatchBean(PointcutAdvisor ad, Class<?> beanClass, List<Method> allMethods) {
                  PointCut p = ad.getPointCut();

                  //匹配類
                  if (!p.matchClass(beanClass)) {
                      return false;
                  }
                  for (Method m : allMethods) {
                      //匹配方法
                      if (p.matchMethod(m, beanClass)) {
                          return true;
                      }
                  }
                  return false;
              }

          判斷是否增強(qiáng)之后,就是需要進(jìn)行代理增強(qiáng)了,那么這里的實(shí)現(xiàn)邏輯又是啥樣的呢

          通過上圖可以看到,需要判斷代理的方式,即使用JDK動態(tài)代理還是CGLIB動態(tài)代碼,那么這里也可以抽象出一個接口。然后不同的代理方式分別去實(shí)現(xiàn)

          定義AopProxy代理接口

          /**
           * @className: AopProxy
           * @description: AOP代理接口,用來創(chuàng)建和獲取代理對象
           * @author: TR
           */
          public interface AopProxy {

              Object getProxy();

              Object getProxy(ClassLoader classLoader);
          }

          JDK動態(tài)代理實(shí)現(xiàn)

          我們知道JDK動態(tài)代理是對接口進(jìn)行的,那么在實(shí)現(xiàn)中需要哪些數(shù)據(jù)呢?

          • 要實(shí)現(xiàn)的接口

          • 目標(biāo)對象

          • 匹配的Advisors

          • BeanFactory

          需要的參數(shù):

          • 需要實(shí)現(xiàn)的接口

          • InvocationHandler

          /**
           * @className: JdkDynamicAopProxy
           * @description: JDK動態(tài)代理實(shí)現(xiàn)
           * @author: TR
           */
          public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
              private static final Logger logger = LoggerFactory.getLogger(JdkDynamicAopProxy.class);

              //bean名稱
              private String beanName;
              //bean對象,需要被代理的對象
              private Object target;
              //通知列表,需要被增強(qiáng)的功能
              private List<Advisor> advisors;
              //當(dāng)前的bean
              private BeanFactory beanFactory;

              public JdkDynamicAopProxy(String beanName, Object target, List<Advisor> advisors, BeanFactory beanFactory) {
                  this.beanName = beanName;
                  this.target = target;
                  this.advisors = advisors;
                  this.beanFactory = beanFactory;
              }

              @Override
              public Object getProxy() {
                  return this.getProxy(target.getClass().getClassLoader());
              }

              @Override
              public Object getProxy(ClassLoader classLoader) {
                  if (logger.isDebugEnabled()) {
                      logger.debug("為" + target + "創(chuàng)建JDK代理。");
                  }
                  return Proxy.newProxyInstance(classLoader, target.getClass().getInterfaces(), this);
              }

              /**
               * InvocationHandler接口的實(shí)現(xiàn)
               * 用來進(jìn)行代理增強(qiáng)后返回實(shí)際的結(jié)果
               */
              @Override
              public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                  return AopProxyUtils.applyAdvices(target, method, args, advisors, proxy, beanFactory);
              }
          }

          CGLIB動態(tài)代理實(shí)現(xiàn)

          CGLIB動態(tài)代理可以對接口和類進(jìn)行,那么它需要下面的數(shù)據(jù):

          • 要繼承的類

          • 要實(shí)現(xiàn)的接口

          • 目標(biāo)對象

          • 匹配的Advisors

          • BeanFactory

          • 構(gòu)造參數(shù)類

          • 構(gòu)造參數(shù)

          需要的參數(shù):

          • 繼承的類

          • 需要實(shí)現(xiàn)的接口

          • Callback

          • 構(gòu)造參數(shù)類型

          • 構(gòu)造參數(shù)

          構(gòu)造參數(shù)類型和構(gòu)造參數(shù)在創(chuàng)建實(shí)例的時候會有的

          /**
           * @className: CglibDynamicAopProxy
           * @description: Cglib動態(tài)代理
           * @author: TR
           */
          public class CglibDynamicAopProxy implements AopProxy, MethodInterceptor {
              private static final Logger logger = LoggerFactory.getLogger(CglibDynamicAopProxy.class);
              private static Enhancer enhancer = new Enhancer();

              //bean名稱
              private String beanName;
              //bean對象,需要被代理的對象
              private Object target;
              //通知列表,需要被增強(qiáng)的功能
              private List<Advisor> advisors;
              //當(dāng)前的bean
              private BeanFactory beanFactory;

              public CglibDynamicAopProxy(String beanName, Object target, List<Advisor> advisors, BeanFactory beanFactory) {
                  this.beanName = beanName;
                  this.target = target;
                  this.advisors = advisors;
                  this.beanFactory = beanFactory;
              }

              @Override
              public Object getProxy() {
                  return this.getProxy(target.getClass().getClassLoader());
              }

              @Override
              public Object getProxy(ClassLoader classLoader) {
                  if (logger.isDebugEnabled()) {
                      logger.debug("為" + target + "創(chuàng)建cglib代理。");
                  }
                  Class<?> superClass = this.target.getClass();
                  enhancer.setSuperclass(superClass);
                  enhancer.setInterfaces(this.getClass().getInterfaces());
                  enhancer.setCallback(this);
                  Constructor<?> constructor = null;

                  try {
                      constructor = superClass.getConstructor(new Class<?>[] {});
                  } catch (NoSuchMethodException e) {
                      e.printStackTrace();
                  }
                  if (constructor != null) {
                      return enhancer.create();
                  } else {
                      BeanDefinition bd = ((DefaultBeanFactory)beanFactory).getBeanDefinition(beanName);
                      return enhancer.create(bd.getConstructor().getParameterTypes(), bd.getConstructorArgumentRealValues());
                  }
              }

              @Override
              public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                  return AopProxyUtils.applyAdvices(target, method, objects, advisors, o, beanFactory);
              }
          }

          AopProxyUtils它是用來干什么的呢,從上面可以看到,這部分的處理,主要是用來實(shí)現(xiàn)增強(qiáng)的,都是使用Advice來增強(qiáng)的,所以增強(qiáng)的邏輯是一樣的

          /**
           * @className: AopProxyUtils
           * @description: aop代理工具類
           * @author: TR
           */
          public class AopProxyUtils {


              /**
               * 對方法應(yīng)用advice增強(qiáng),獲得最終返回結(jié)果
               * @author: TR
               * @param target: 需要被增強(qiáng)的對象
               * @param method: 需要被增強(qiáng)的方法
               * @param args: 增強(qiáng)方法的參數(shù)
               * @param advisors: 匹配到的切面
               * @param proxy: bean對象功能增強(qiáng)后的代理對象
               * @param beanFactory: bean工廠
               * @return: java.lang.Object
               **/
              public static Object applyAdvices(Object target, Method method, Object[] args, List<Advisor> advisors,
                                                Object proxy, BeanFactory beanFactory) throws Throwable {
                  //獲取對當(dāng)前方法進(jìn)行增強(qiáng)的advices
                  List<Object> advices = AopProxyUtils.getShouldApplyAdvices(target.getClass(), method, advisors, beanFactory);
                  if (CollectionUtils.isEmpty(advices)) {
                      return method.invoke(target, args);
                  } else {
                      //使用責(zé)任鏈進(jìn)行增強(qiáng)
                      AopAdviceChainInvocation ac = new AopAdviceChainInvocation(proxy, target, method, args, advices);
                      return ac.invoke();
                  }
              }

              /**
               * 獲得與方法匹配的Advice切面列表
               * @author: TR
               * @param aClass:
               * @param method:
               * @param advisors:
               * @param beanFactory:
               * @return: java.util.List<demo.aop.advice.Advice>
               **/
              private static List<Object> getShouldApplyAdvices(Class<?> aClass, Method method,
                                                                List<Advisor> advisors, BeanFactory beanFactory) throws Exception {
                  if (CollectionUtils.isEmpty(advisors)) {
                      return null;
                  }
                  List<Object> advices = new ArrayList<>();
                  for (Advisor advisor : advisors) {
                      if (advisor instanceof PointcutAdvisor) {
                          if (((PointcutAdvisor)advisor).getPointCut().matchMethod(method, aClass)) {
                              advices.add(beanFactory.getBean(advisor.getAdviceBeanName()));
                          }
                      }
                  }
                  return advices;
              }
          }

          如何來傳遞創(chuàng)建bean實(shí)例時獲得的數(shù)據(jù)到初始化后的Aop中,就是要在BeanDefinition中使用ThreadLocal持有參數(shù)值

          BeanDefinition增加如下方法:

             /** 獲取構(gòu)造參數(shù)值 */
              public Object[] getConstructorArgumentRealValues();

              /** 設(shè)置構(gòu)造參數(shù)值 */
              public void setConstructorArgumentRealValues(Object[] values);

          GeneralBeanDefinition類中相應(yīng)的實(shí)現(xiàn):

             private ThreadLocal<Object[]> realConstructorArgumentValues = new ThreadLocal<>();

              @Override
              public Object[] getConstructorArgumentRealValues() {
                  return realConstructorArgumentValues.get();
              }

              @Override
              public void setConstructorArgumentRealValues(Object[] values) {
                 this.realConstructorArgumentValues.set(values);
              }

          責(zé)任鏈AopAdviceChainInvocation類

          /**
           * @className: AopAdviceChainInvocation
           * @description: AOP責(zé)任鏈調(diào)用類
           * @author: TR
           */
          public class AopAdviceChainInvocation {

              /** AOP責(zé)任鏈執(zhí)行的方法 */
              private static Method invokeMethod;

              static {
                  try {
                      invokeMethod = AopAdviceChainInvocation.class.getMethod("invoke", null);
                  } catch (NoSuchMethodException e) {
                      e.printStackTrace();
                  }
              }

              //代理類對象
              private Object proxy;
              //目標(biāo)類對象
              private Object target;
              //調(diào)用執(zhí)行的對象方法
              private Method method;
              //執(zhí)行方法的參數(shù)
              private Object[] args;
              //方法被增強(qiáng)的功能:通知列表
              private List<Object> advices;

              public AopAdviceChainInvocation(Object proxy, Object target, Method method, Object[] args, List<Object> advices) {
                    this.proxy = proxy;
                    this.target = target;
                    this.method = method;
                    this.args = args;
                    this.advices = advices;
              }

              //責(zé)任鏈執(zhí)行記錄的索引號
              private int i = 0;

              public Object invoke() throws Throwable {
                  if (i < this.advices.size()) {
                      Object advice = this.advices.get(i++);
                      if (advice instanceof MethodBeforeAdvice) {
                          //執(zhí)行前增強(qiáng)
                          ((MethodBeforeAdvice)advice).before(method, target, args);
                      } else if (advice instanceof MethodInterceptor) {
                          //執(zhí)行環(huán)繞增強(qiáng)和異常增強(qiáng),這里給的method和對象是invoke方法和鏈對象
                          ((MethodInterceptor)advice).invoke(invokeMethod,this, null);
                      } else if (advice instanceof AfterReturningAdvice) {
                          //后置增強(qiáng),先獲得結(jié)果,在增強(qiáng)
                          Object returnValue = this.invoke();
                          ((AfterReturningAdvice)advice).after(method, target, args, returnValue);
                          return returnValue;
                      }
                      //回調(diào)
                      return this.invoke();
                  } else {
                      return method.invoke(target, args);
                  }
              }
          }

          定義AopProxyFactory接口

          代理的方式實(shí)現(xiàn)完了之后,就需要使用它了,這里使用工廠模式實(shí)現(xiàn):

          /**
           * @className: AopProxyFactory
           * @description: AOP代理的工廠接口
           * @author: TR
           */
          public interface AopProxyFactory {

              /**
               * 根據(jù)參數(shù)獲取AOP代理接口的實(shí)現(xiàn)
               * @param bean: 實(shí)例
               * @param beanName: bean名稱
               * @param advisors: advisors列表
               * @param beanFactory: bean工廠
               * @return: AopProxyFactory
               **/
              AopProxy createAopProxy(Object bean, String beanName, List<Advisor> advisors, BeanFactory beanFactory);

              /**
               * 獲取默認(rèn)的AopProxyFactory
               * @return: AopProxyFactory
               **/
              static AopProxyFactory getDefaultAopProxyFactory() {
                  return new DefaultAopProxyFactory();
              }
          }

          實(shí)現(xiàn)類:

          /**
           * @className: DefaultAopProxyFactory
           * @description: 代理工廠實(shí)現(xiàn)類
           * @author: TR
           */
          public class DefaultAopProxyFactory implements AopProxyFactory {

              @Override
              public AopProxy createAopProxy(Object bean, String beanName, List<Advisor> advisors, BeanFactory beanFactory) {
                  //是用JDK動態(tài)代理還是CGLIB動態(tài)代理
                  if (shouldUseJDKDynamicProxy(bean, beanName)) {
                      return new JdkDynamicAopProxy(beanName, bean, advisors, beanFactory);
                  } else {
                      return new CglibDynamicAopProxy(beanName, bean, advisors, beanFactory);
                  }
              }

              private boolean shouldUseJDKDynamicProxy(Object bean, String beanName) {
                  return false;
              }
          }

          下面需要修改下AdvisorAutoProxyCreator類中的postProcessAfterInitialization方法:

              @Override
              public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
                  //判斷是否需要進(jìn)行切面增強(qiáng),及獲得增強(qiáng)的通知實(shí)現(xiàn)
                  List<Advisor> advisors = getMatchedAdvisors(bean, beanName);
                  //如果需要增強(qiáng),返回增強(qiáng)后的對象
                  if (CollectionUtils.isNotEmpty(advisors)) {
                      //使用代理模式進(jìn)行功能增強(qiáng)
                      bean = this.createProxy(bean, beanName, advisors);
                  }
                  return bean;
              }
              
              private Object createProxy(Object bean, String beanName, List<Advisor> advisors) {
                  return AopProxyFactory.getDefaultAopProxyFactory()
                          .createAopProxy(bean, beanName, advisors, beanFactory)
                          .getProxy();
              }

          DefaultBeanFactory類中緩存構(gòu)造函數(shù)的方式需要改變一下

          determineConstructor方法中緩存的代碼注釋掉:

          if (ct != null) {
          //            //對于原型bean,緩存起來
          //            if (bd.isProtoType()) {
          //                bd.setConstructor(ct);
          //            }
                      return ct;
                  } else {
                      throw new Exception("找不到對應(yīng)的構(gòu)造方法:" + bd);
                  }

          在createBeanByConstructor中增加代碼

           /** 通過構(gòu)造函數(shù)構(gòu)建bean */
              private Object createBeanByConstructor(BeanDefinition bd) throws Exception {
                  Object object = null;
                  if (CollectionUtils.isEmpty(bd.getConstructorArgumentValues())) {
                      //獲得的構(gòu)造參數(shù)值是空的,就不傳參
                      object = bd.getBeanClass().newInstance();
                  } else {
                      //獲得的參數(shù)值是空的,就不傳參
                      Object[] args = getConstructorArgumentValues(bd);
                      if (args == null) {
                          object = bd.getBeanClass().newInstance();
                      } else {
                          // 根據(jù)參數(shù)匹配決定構(gòu)造方法,然后進(jìn)行實(shí)例化調(diào)用
                          bd.setConstructorArgumentRealValues(args);
                          Constructor<?> ct = this.determineConstructor(bd, args);
                          // 緩存構(gòu)造函數(shù)由determineConstructor 中移到了這里,無論原型否都緩存,因?yàn)楹竺鍭OP需要用
                          bd.setConstructor(ct);
                          return ct.newInstance(args);
                      }
                  }
                  return object;
              }

          測試一下

          前置增強(qiáng)實(shí)現(xiàn):

          public class MyBeforeAdvice implements MethodBeforeAdvice {

              @Override
              public void before(Method method, Object target, Object[] args) {
                  System.out.println(this + " 對 " + target + " 進(jìn)行了前置增強(qiáng)!");
              }
          }

          后置增強(qiáng)實(shí)現(xiàn):

          public class MyAfterReturningAdvice implements AfterReturningAdvice {

              @Override
              public void after(Method method, Object target, Object[] args, Object returnValue) {
                  System.out.println(this + " 對 " + target + " 做了后置增強(qiáng),得到的返回值=" + returnValue);
              }
          }

          環(huán)繞增強(qiáng)實(shí)現(xiàn):

          public class MyMethodInterceptor implements MethodInterceptor {

              @Override
              public Object invoke(Method method, Object target, Object[] args) throws Throwable {
                  System.out.println(this + "對 " + target + "進(jìn)行了環(huán)繞--前增強(qiáng)");
                  Object ret = method.invoke(target, args);
                  System.out.println(this + "對 " + target + "進(jìn)行了環(huán)繞 --后增強(qiáng)。方法的返回值為:" + ret);
                  return ret;
              }
          }

          測試類:

          public class AopTest {
              static PreBuildBeanFactory bf = new PreBuildBeanFactory();

              @Test
              public void testCirculationDI() throws Throwable {

                  GeneralBeanDefinition bd = new GeneralBeanDefinition();
                  bd.setBeanClass(Lad.class);
                  List<Object> args = new ArrayList<>();
                  args.add("孫悟空");
                  args.add(new BeanReference("baigujing"));
                  bd.setConstructorArgumentValues(args);
                  bf.registerBeanDefinition("swk", bd);

                  bd = new GeneralBeanDefinition();
                  bd.setBeanClass(MagicGirl.class);
                  args = new ArrayList<>();
                  args.add("白骨精");
                  bd.setConstructorArgumentValues(args);
                  bf.registerBeanDefinition("baigujing", bd);

                  bd = new GeneralBeanDefinition();
                  bd.setBeanClass(Renminbi.class);
                  bf.registerBeanDefinition("renminbi", bd);

                  // 前置增強(qiáng)advice bean注冊
                  bd = new GeneralBeanDefinition();
                  bd.setBeanClass(MyBeforeAdvice.class);
                  bf.registerBeanDefinition("myBeforeAdvice", bd);

                  // 環(huán)繞增強(qiáng)advice bean注冊
                  bd = new GeneralBeanDefinition();
                  bd.setBeanClass(MyMethodInterceptor.class);
                  bf.registerBeanDefinition("myMethodInterceptor", bd);

                  // 后置增強(qiáng)advice bean注冊
                  bd = new GeneralBeanDefinition();
                  bd.setBeanClass(MyAfterReturningAdvice.class);
                  bf.registerBeanDefinition("myAfterReturningAdvice", bd);

                  // 往BeanFactory中注冊AOP的BeanPostProcessor
                  AdvisorAutoProxyCreator aapc = new AdvisorAutoProxyCreator();
                  bf.registerBeanPostProcessor(aapc);
                  // 向AdvisorAutoProxyCreator注冊Advisor
                  aapc.registerAdvisor(
                          new AspectJPointcutAdvisor("myBeforeAdvice""execution(* demo.di.MagicGirl.*(..))"));
                  // 向AdvisorAutoProxyCreator注冊Advisor
                  aapc.registerAdvisor(
                          new AspectJPointcutAdvisor("myMethodInterceptor""execution(* demo.di.Lad.say*(..))"));
                  // 向AdvisorAutoProxyCreator注冊Advisor
                  aapc.registerAdvisor(new AspectJPointcutAdvisor("myAfterReturningAdvice",
                          "execution(* demo.di.Renminbi.*(..))"));

                  bf.preInstantiateSingletons();

                  System.out.println("-----------------myBeforeAdvice---------------");
                  MagicGirl gril = (MagicGirl) bf.getBean("baigujing");
                  gril.getFriend();
                  gril.getName();

                  System.out.println("----------------myMethodInterceptor----------------");
                  Boy boy = (Boy) bf.getBean("swk");
                  boy.sayLove();

                  System.out.println("-----------------myAfterReturningAdvice---------------");
                  Renminbi rmb = (Renminbi) bf.getBean("renminbi");
                  rmb.pay();
              }
          }

          運(yùn)行結(jié)果:









          鋒哥最新SpringCloud分布式電商秒殺課程發(fā)布

          ??????

          ??長按上方微信二維碼 2 秒





          感謝點(diǎn)贊支持下哈 

          瀏覽 81
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  大鸡巴操小穴高潮视频 | 亚洲色播中文字幕 | 一道本一二三区 | 亚洲电影欧美片日韩 | 淫婷婷|