<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>

          AspectJ一文說明白

          共 13995字,需瀏覽 28分鐘

           ·

          2021-01-12 01:35


          Aspectj與Spring AOP比較參考:https://www.jianshu.com/p/872d3dbdc2ca

          XML配置方式

          • :定義切面, 包括通知和切點. 是一般的bean
            //定義切面
            public class SleepHelperAspect{
            public void beforeSleep(){
            System.out.println("睡覺前要脫衣服!");
            }

            public void afterSleep(){
            System.out.println("起床后要穿衣服!");
            }
            }

            <bean id="sleepHelperAspect" class="com.ghs.aop.SleepHelperAspect">bean>

            <aop:aspectj-autoproxy/>
            <aop:config>
            <aop:pointcut expression="execution(* *.sleep(..))" id="sleepPointcut"/>
            <aop:aspect ref="sleepHelperAspect">

            <aop:before method="beforeSleep" pointcut-ref="sleepPointcut"/>

            <aop:after method="afterSleep" pointcut-ref="sleepPointcut"/>
            aop:aspect>
            aop:config>?
          •   定義通知器, 跟切面一樣,也包括通知(advice)和切點(PointCut) . 通知必須實現(xiàn)Advice接口.
            //定義通知
            public class SleepHelper implements MethodBeforeAdvice,AfterReturningAdvice{
            @Override
            public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
            System.out.println("睡覺前要脫衣服!");
            }

            @Override
            public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
            System.out.println("起床后要穿衣服!");
            }
            }
            <bean id="sleepHelper" class="com.noob.aop.SleepHelper">bean>

            <aop:aspectj-autoproxy/>
            <aop:config>
            <aop:pointcut expression="execution(* *.sleep(..))" id="sleepPointcut"/>
            <aop:advisor advice-ref="sleepHelper" pointcut-ref="sleepPointcut"/>
            aop:config>

          基本概念

          1. Advice(通知、切面):某個連接點所采用的處理邏輯,也就是向連接點注入的代碼, AOP在特定的切入點上執(zhí)行的增強處理。

          2. JointPoint(連接點):程序運行中的某個階段點,比如方法的調(diào)用、異常的拋出等。

          3. Pointcut(切入點):? ?JoinPoint的集合,是程序中需要注入Advice的位置的集合,指明Advice要在什么樣的條件下才能被觸發(fā),在程序中主要體現(xiàn)為書寫切入點表達式。

          4. Advisor(增強):?PointCut 和 Advice的綜合體完整描述了一個advice將會在pointcut所定義的位置被觸發(fā)。

          5. @Aspect(切面):? 通常是一個類的注解,類中可以定義切入點和通知

          6. AOP Proxy:AOP框架創(chuàng)建的對象,代理就是目標對象的加強。Spring中的AOP代理可以使JDK動態(tài)代理,也可以是CGLIB代理,前者基于接口,后者基于子類。

          Pointcut

          表示式(expression)和簽名(signature)

          //Pointcut表示式
          @Pointcut("execution(* com.savage.aop.MessageSender.*(..))")
          //Point簽名
          private void log(){}

          由下列方式來定義或者通過 &&、?||、 !、?的方式進行組合:

          • execution:匹配 方法執(zhí)行的連接點;

          • within:?目標對象target的類型是否和within中指定的類型匹配?。參數(shù)可指定包路徑或具體的類全路徑名。
            ?匹配原則:target.getClass().equals(within表達式中指定的類型)

          • this(類型全限定名):?通過aop創(chuàng)建的代理對象的類型是否和this中指定的類型匹配;注意判斷的目標是代理對象;this中使用的表達式必須是類型全限定名,不支持通配符。
            ?匹配原則:this(x),則代理對象proxy滿足下面條件時會匹配: x.getClass().isAssignableFrom(proxy.getClass());???

          • target(類型全限定名):?判斷目標對象的類型是否和指定的類型匹配;注意判斷的目標是實際對象的類型;表達式必須是類型全限定名,不支持通配符。
            ?匹配原則:?target(x),則目標對象target滿足下面條件時會匹配 x.getClass().isAssignableFrom(target.getClass());

          • args:匹配 當前執(zhí)行的方法傳入的參數(shù)為指定類型的執(zhí)行方法;

          • @within:自定義注解標注在類上,該類的所有方法(不包含子類方法)執(zhí)行aop方法

          • @target:匹配 當前目標對象類型的執(zhí)行方法,其中目標對象類持有指定的注解;

          • @args:當前執(zhí)行的方法傳入的參數(shù)持有指定注解;

          • @annotation:匹配 執(zhí)行方法持有指定注解;

          格式

          execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)   其中后面跟著“?”的是可選項

          括號中各個pattern分別表示:

          • 修飾符匹配(modifier-pattern?)

          • 返回值匹配(ret-type-pattern):? ?可以為*表示任何返回值, 全路徑的類名等

          • 類路徑匹配(declaring-type-pattern?)

          • 方法名匹配(name-pattern):可以指定方法名 或者 *代表所有, set* 代表以set開頭的所有方法

          • 參數(shù)匹配((param-pattern)):可以指定具體的參數(shù)類型。多個參數(shù)間用“,”隔開,各個參數(shù)也可以用"*"?來表示匹配任意類型的參數(shù),".."表示零個或多個任意參數(shù)。
            eg. (String)表示匹配一個String參數(shù)的方法;(*,String) 表示匹配有兩個參數(shù)的方法,第一個參數(shù)可以是任意類型,而第二個參數(shù)是String類型。

          • 異常類型匹配(throws-pattern?)

          • 任意公共方法的執(zhí)行:execution(public * *(..))

          • 任何一個以“set”開始的方法的執(zhí)行:execution(* set*(..))

          • AccountService 接口的任意方法的執(zhí)行:execution(* com.xyz.service.AccountService.*(..))

          • 定義在service包里的任意方法的執(zhí)行:?execution(* com.xyz.service.*.*(..))

          • 定義在service包和所有子包里的任意類的任意方法的執(zhí)行:execution(* com.xyz.service..*.*(..))
            第一個*表示匹配任意的方法返回值, ..(兩個點)表示零個或多個,第一個..表示service包及其子包,第二個*表示所有類, 第三個*表示所有方法,第二個..表示方法的任意參數(shù)個數(shù)

          • 定義在pointcutexp包和所有子包里的JoinPointObjP2類的任意方法的執(zhí)行:execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")

          • pointcutexp包里的任意類:?within(com.test.spring.aop.pointcutexp.*)

          • pointcutexp包和所有子包里的任意類:within(com.test.spring.aop.pointcutexp..*)

          • 實現(xiàn)了Intf接口的所有類,如果Intf不是接口,限定Intf單個類:this(com.test.spring.aop.pointcutexp.Intf)
            當一個實現(xiàn)了接口的類被AOP的時候,用getBean方法必須cast為接口類型,不能為該類的類型

          • 帶有@Transactional標注的所有類的任意方法:?

            • @within(org.springframework.transaction.annotation.Transactional)

            • @target(org.springframework.transaction.annotation.Transactional)

          • 帶有@Transactional標注的任意方法:@annotation(org.springframework.transaction.annotation.Transactional)
            @within和@target針對類的注解,@annotation是針對方法的注解

          • 參數(shù)帶有@Transactional標注的方法:@args(org.springframework.transaction.annotation.Transactional)

          • 參數(shù)為String類型(運行是決定)的方法:?args(String)

          JoinPoint

          1. @Before:?AspectJMethodBeforeAdvice標識一個前置增強方法.

          2. @After?AspectJAfterAdvicefinal增強,不管是拋出異?;蛘哒M顺龆紩?zhí)行.

          3. @AfterReturning:??AspectJAfterReturningAdvice后置增強,方法正常退出時執(zhí)行.

          4. @AfterThrowing:??AspectJAfterThrowingAdvice異常拋出增強.

          5. @Around:?AspectJAroundAdvice環(huán)繞增強.

          常用的方法:

          • Object[] getArgs:返回目標方法的參數(shù)

          • Signature getSignature():返回目標方法的簽名信息??色@取方法名等

          • Object getTarget():返回被織入增強處理的目標對象

          • Object getThis():返回AOP框架為目標對象生成的代理對象

          使用@Around處理時,需要將第一個JoinPoint參數(shù)定義為ProceedingJoinPoint類型才可使用方法proceed。?

          因為在org.springframework.aop.aspectj.AbstractAspectJAdvice?里默認supportsProceedingJoinPoint()為false; 而AspectJAroundAdvice重寫為true;

          Caused by: java.lang.IllegalArgumentException: ProceedingJoinPoint is only supported for around advice
          ?? ?at org.springframework.aop.aspectj.AbstractAspectJAdvice.maybeBindProceedingJoinPoint(AbstractAspectJAdvice.java:414) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.aspectj.AbstractAspectJAdvice.calculateArgumentBindings(AbstractAspectJAdvice.java:388) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.getAdvice(ReflectiveAspectJAdvisorFactory.java:294) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl.instantiateAdvice(InstantiationModelAwarePointcutAdvisorImpl.java:149) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl.<init>(InstantiationModelAwarePointcutAdvisorImpl.java:113) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.getAdvisor(ReflectiveAspectJAdvisorFactory.java:198) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.getAdvisors(ReflectiveAspectJAdvisorFactory.java:126) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors(BeanFactoryAspectJAdvisorsBuilder.java:110) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors(AnnotationAwareAspectJAutoProxyCreator.java:95) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator.shouldSkip(AspectJAwareAdvisorAutoProxyCreator.java:101) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessBeforeInstantiation(AbstractAutoProxyCreator.java:251) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:1124) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:1097) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:504) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?... 15 common frames omitted

          spring-core模塊中:? 提供支持cgliborg.springframework.cglib.proxy.MethodInterceptor是給?org.springframework.cglib.proxy.Enhancer使用的?org.springframework.cglib.proxy.Callback

          public interface MethodInterceptor extends Callback {
          Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
          }

          spring-aop模塊中:org.aopalliance.intercept.MethodInterceptor根本上是一個org.aopalliance.aop.Advice

          public interface MethodInterceptor extends Interceptor {
          Object invoke(MethodInvocation invocation) throws Throwable;
          }

          public interface Interceptor extends Advice {}

          織入

               @AfterReturning(
          pointcut="execution(* com.abc.service.*.access*(..)) && args(time, name)",
          returning="returnValue")

          public void invoke(Date time, Object returnValue, String name) {
          System.out.println("目標方法中的參數(shù)String = " + name);
          System.out.println("目標方法中的參數(shù)Date = " + time);
          System.out.println("目標方法的返回結(jié)果returnValue = " + returnValue);
          }

          表達式中增加了args(time, name)部分,意味著可以在增強處理的簽名方法(access方法中定義"time"和"name"兩個同名屬性。這兩個形參的類型由access方法同名參數(shù)類型指定。一旦指定了, 則這兩個形參類型將用于限制該切入點只匹配第一個參數(shù)類型為Date,第二個參數(shù)類型為String的方法(方法參數(shù)個數(shù)和類型若有不同均不匹配);
          access方法只需要滿足"time", "name"參數(shù)的順序和pointcut中args(time, name)的順序相同即可,"returnValue"位置順序無所謂。?

          eg.

          //將被access方法匹配
          public String accessAdvice(Date d, String n) {
          System.out.println("方法:accessAdvice");
          return "aa";
          }

          執(zhí)行順序

          package com.noob.controller.Interceptor;

          import org.aspectj.lang.JoinPoint;
          import org.aspectj.lang.ProceedingJoinPoint;
          import org.aspectj.lang.annotation.After;
          import org.aspectj.lang.annotation.AfterReturning;
          import org.aspectj.lang.annotation.AfterThrowing;
          import org.aspectj.lang.annotation.Around;
          import org.aspectj.lang.annotation.Aspect;
          import org.aspectj.lang.annotation.Before;
          import org.aspectj.lang.annotation.Pointcut;
          import org.springframework.stereotype.Component;

          @Aspect
          @Component
          public class AdviceInterceptor {
          @Pointcut(value = "execution(public String com.noob.controller.BService.testAdvice(..))")
          public void pointcut() {}

          @Before("pointcut()")
          public void before(JoinPoint point) {
          System.out.println("before");
          }

          @Around("pointcut()")
          public Object around(ProceedingJoinPoint point) throws Throwable {
          System.out.println("around begin");
          try {
          Object proceed = point.proceed();
          System.out.println("around after");
          return proceed;
          } catch (Throwable e) {
          System.out.println("around after exception");
          throw e;
          }
          }

          @After("pointcut()")
          public void after() throws Throwable {
          System.out.println("after");
          }

          @AfterReturning("pointcut()")
          public void afterReturning() throws Throwable {
          System.out.println("afterReturning");
          }

          @AfterThrowing("pointcut()")
          public void afterThrowing() {
          System.out.println("afterThrowing");
          }
          }
          ---
          @Component
          public class BService {

          public String testAdvice() {
          System.out.println("目標方法testAdvice");
          throw new RuntimeException("fail");
          // return "testAdvice";
          }
          }

          正常情況執(zhí)行結(jié)果:

          around begin
          before
          目標方法testAdvice
          around after
          after
          afterReturning

          有異常情況下:

          around begin
          before
          目標方法testAdvice
          around after exception
          after
          afterThrowing

          測試過程中發(fā)現(xiàn),debug模式下可知JoinPoint的實際類型是org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint(before、around 都是該實際類型)

          但若代碼直接寫定該類型,啟動報錯

          Caused by: java.lang.IllegalArgumentException: error at ::0 formal unbound in pointcut?
          ?? ?at org.aspectj.weaver.tools.PointcutParser.parsePointcutExpression(PointcutParser.java:319) ~[aspectjweaver-1.9.4.jar:na]
          ?? ?at org.springframework.aop.aspectj.AspectJExpressionPointcut.buildPointcutExpression(AspectJExpressionPointcut.java:227) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.aspectj.AspectJExpressionPointcut.obtainPointcutExpression(AspectJExpressionPointcut.java:198) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.aspectj.AspectJExpressionPointcut.getClassFilter(AspectJExpressionPointcut.java:177) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:225) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:288) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:320) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:126) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:95) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:76) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:347) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:299) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:429) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1782) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?? ?at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]

          因為, 執(zhí)行到ReflectiveAspectJAdvisorFactory.getAdvisors -> ReflectiveAspectJAdvisorFactory.getAdvice -> AbstractAspectJAdvice.calculateArgumentBindings()時:JoinPoint.classProceedingJoinPoint.class是不用額外處理參數(shù)綁定。

          所以MethodInvocationProceedingJoinPoint被當作額外的參數(shù)。

          后續(xù)先執(zhí)行進入org.aspectj.weaver.tools.PointcutParser.parsePointcutExpression -> PointcutParser.resolvePointcutExpression:

          PointcutParser.buildResolutionScope創(chuàng)建參數(shù)類型綁定關(guān)系。

          接著執(zhí)行進入org.aspectj.weaver.patterns.Pointcut.resolve:

          首先?Pointcut.resolveBindings來根據(jù)實際情況解析該綁定關(guān)系;接著執(zhí)行校驗方法Bindings.checkAllBound因真實綁定為空,判定失敗后異常

          同一個方法被多個Aspect類攔截

          優(yōu)先級高的切面類里的增強處理 優(yōu)先于? 優(yōu)先級低的切面類。? ? ? ?

          在“進入”連接點時,最高優(yōu)先級的增強處理將先被織入(eg. 給定的兩個不同切面類Before增強處理中,優(yōu)先級高的那個會先執(zhí)行);

          在“退出”連接點時,最高優(yōu)先級的增強處理會最后被織入(eg. 給定的兩個不同切面類After增強處理中,優(yōu)先級高的那個會后執(zhí)行)。

          eg.?優(yōu)先級為1的切面類Bean1包含了@Before,優(yōu)先級為2的切面類Bean2包含了@Around,雖然@Around優(yōu)先級高于@Before,但由于Bean1的優(yōu)先級高于Bean2的優(yōu)先級,因此Bean1中的@Before先被織入。

          Spring提供了如下兩種解決方案指定不同切面類里的增強處理的優(yōu)先級:

          1. 讓切面類實現(xiàn)org.springframework.core.Ordered接口:實現(xiàn)該接口的int getOrder()方法,該方法返回值越小,優(yōu)先級越高

          2. 直接使用@Order注解來修飾一個切面類:使用這個注解時可以配置一個int類型的value屬性,該屬性值越小,優(yōu)先級越高

          同一個切面類里的兩個相同類型的增強處理在同一個連接點被織入時,Spring AOP將以隨機的順序來織入這兩個增強處理,沒有辦法指定它們的織入順序。即使給這兩個 advice 添加了 @Order 這個注解,也不行!

          喜歡,在看


          瀏覽 50
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  五月丁香婷色 | 骚碰人人看 | 色九九九九 | 亚洲AV五月天草榴 | 日本一级红色片 |