對哪些方法進行攔截,攔截後怎麼處理,這些關注點稱之爲橫切關注點html
類是對物體特徵的抽象,切面就是對橫切關注點的抽象。 通知+切點 意思就是全部要被應用到加強(advice)代碼的地方。(包括方法的方位信息)java
被攔截到的點,由於Spring只支持方法類型的鏈接點,因此在Spring中鏈接點指的就是被攔截的方法,實際上鍊接點還能夠是字段或者構造器git
對鏈接點進行攔截的定義github
所謂通知指的就是指攔截到鏈接點以後要執行的代碼,通知分爲前置、後置、異常、最終、環繞通知五類 這玩意也叫 加強 在邏輯層次上包括了咱們抽取的公共邏輯和方位信息。由於Spring只能方法級別的應用AOP,也就是咱們常見的before,after,after-returning,after-throwing,around五種,意思就是在方法調用先後,異常時候執行我這段公共邏輯唄。web
代理的目標對象spring
將切面應用到目標對象並致使代理對象建立的過程。 好比根據Advice中的方位信息在指定切點的方法先後,執行加強。這個過程Spring 替咱們作好了。利用的是CGLIB動態代理技術。spring-boot
在不修改代碼的前提下,引入能夠在運行期爲類動態地添加一些方法或字段this
上面那一堆看不懂對嗎? 我也不太懂。 來看張圖 阿里雲
切面一共有五種通知spa
前置通知(Before advice) :在某鏈接點(JoinPoint)以前執行的通知, 但這個通知不能阻止鏈接點前的執行。在方法調用以前發出通
@Before("execution(* com.slife.java8.aspect.AspectTest.test())") public void beforeTest() { System.out.println("執行 方法 以前 調用----"); }
後通知(After advice) :當某鏈接點退出的時候執行的通知(不管是正常 返回仍是異常退出)。 不考慮方法運行的結果 。在方法調用以後發出通
@After("execution(* com.slife.java8.aspect.AspectTest.test())") public void afterTest() { System.out.println(); System.out.println("執行 方法 以後 調用----"); }
方法正常返回後,調用通知。在方法調用後,正常退出發出通
@AfterReturning("execution(* com.slife.java8.aspect.AspectTest.test())") public void afterReturningTest() { System.out.println(); System.out.println("執行 方法 AfterReturning 調用----"); }
拋出異常後通知(After throwing advice) : 在方法拋出異常退出時執行 的通知。在方法調用時,異常退出發出通
@AfterThrowing("execution(* com.slife.java8.aspect.AspectTest.test())") public void afterThrowingTest() { System.out.println(); System.out.println("執行 方法 AfterThrowing 調用----"); }
環繞通知(Around advice) :包圍一個鏈接點的通知,相似Web中Servlet 規範中的Filter的doFilter方法。能夠在方法的調用先後完成自定義的行爲,也能夠選擇不執行。在方法調用以前和以後發出通
@Around("execution(* com.slife.java8.aspect.AspectTest.test())") public void aroundTest() { System.out.println(); System.out.println("執行 方法 先後 調用----"); }
2017-10-27 19:51:51.605 DEBUG 15592 --- [io-8081-exec-10] o.s.web.servlet.DispatcherServlet : Last-Modified value for [/aspecttest] is: -1 執行 方法 以前 調用---- JoinpointTest++++執行我正常流水線的業務邏輯 執行 方法 以後 調用---- 執行 方法 AfterReturning 調用---- 2017-10-27 19:51:51.622 DEBUG 15592 --- [io-8081-exec-10] o.s.web.servlet.DispatcherServlet : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling 2017-10-27 19:51:51.622 DEBUG 15592 --- [io-8081-exec-10] o.s.web.servlet.DispatcherServlet : Successfully completed request
切入點指示符用來指示切入點表達式目的,在Spring AOP中目前只有執行方法這一個鏈接點,Spring AOP支持的AspectJ切入點指示符以下:
args() 定製join-point去匹配那些參數爲指定類型的方法的執行動做。 @args() 定製join-point去匹配那些參數被指定類型註解的方法的執行動做 execution() 開始匹配在其內部編寫的定製 this() 定製join-pont去匹配由AOP代理的Bean引用的指定類型的類。 target() 定製join-point去匹配特定的對象,這些對象必定是指定類型的類。 @target() 定製join-point去匹配特定的對象,這些對象要具備的指定類型的註解。 within() 定製join-point在必須哪個包中。 @within() 定製join-point在必須由指定註解標註的類中。 @annotation 定製鏈接點具備指定的註解。 只有execution用來執行匹配,其餘標誌符都只是爲了限制/定製他們所要匹配的鏈接點的位置。
*
:匹配任何數量字符。
..
:匹配任何數量字符的重複,如在類型模式中匹配任何數量子包;而在方法參數模式中匹配任何數量參數。
+
:匹配指定類型的子類型;僅能做爲後綴放在類型模式後邊。
java.lang.String 匹配String類型; java.*.String 匹配java包下的任何「一級子包」下的String類型; 如匹配java.lang.String,但不匹配java.lang.ss.String java..* 匹配java包及任何子包下的任何類型; 如匹配java.lang.String、java.lang.annotation.Annotation java.lang.*ing 匹配任何java.lang包下的以ing結尾的類型; java.lang.Number+ 匹配java.lang包下的任何Number的自類型; 如匹配java.lang.Integer,也匹配java.math.BigInteger
註解? 修飾符? 返回值類型 類型聲明?方法名(參數列表) 異常列表? 註解:可選,方法上持有的註解,如@Deprecated; 修飾符:可選,如public、protected; 返回值類型:必填,能夠是任何類型模式;「*」表示全部類型; 類型聲明:可選,能夠是任何類型模式; 方法名:必填,可使用「*」進行模式匹配; 參數列表:「()」表示方法沒有任何參數;「(..)」表示匹配接受任意個參數的方法,「(..,java.lang.String)」表示匹配接受java.lang.String類型的參數結束,且其前邊能夠接受有任意個參數的方法;「(java.lang.String,..)」 表示匹配接受java.lang.String類型的參數開始,且其後邊能夠接受任意個參數的方法;「(*,java.lang.String)」 表示匹配接受java.lang.String類型的參數結束,且其前邊接受有一個任意類型參數的方法; 異常列表:可選,以「throws 異常全限定名列表」聲明,異常全限定名列表若有多個以「,」分割,如throws java.lang.IllegalArgumentException, java.lang.ArrayIndexOutOfBoundsException。 匹配Bean名稱:可使用Bean的id或name進行匹配,而且可以使用通配符「*」;
AspectJ使用 且(&&)、或(||)、非(!)來組合切入點表達式。在Schema風格下,因爲在XML中使用「&&」須要使用轉義字符「&&」來代替之,因此很不方便,所以Spring ASP 提供了and、or、not來代替&&、||、!。
使用JoinPoint獲取:Spring AOP提供使用org.aspectj.lang.JoinPoint類型獲取鏈接點數據,任何通知方法的第一個參數均可以是JoinPoint(環繞通知是ProceedingJoinPoint,JoinPoint子類),固然第一個參數位置也能夠是JoinPoint.StaticPart類型,這個只返回鏈接點的靜態部分。
AOP 、IOC 作爲Spring 的支柱,使用場景很是普遍。
##三、事務
動態代理 Spring中AOP代理由Spring的IOC容器負責生成、管理,其依賴關係也由IOC容器負責管理。所以,AOP代理能夠直接使用容器中的其它bean實例做爲目標,這種關係可由IOC容器的依賴注入提供。Spring建立代理的規則爲:
一、默認使用Java動態代理來建立AOP代理,這樣就能夠爲任何接口實例建立代理了
二、當須要代理的類不是代理接口的時候,Spring會切換爲使用CGLIB代理,也可強制使用CGLIB
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
@Aspect // FOR AOP @Order(-99) // 控制多個Aspect的執行順序,越小越先執行 @Component public class AdviceTest { @Pointcut(value="execution(* com.slife.java8.aspect.AspectTest.test())") public void poincut(){ } @Before("poincut()") public void beforeTest() { System.out.println("執行 方法 以前 調用----"); } }
這樣就完成了在spring boot 項目中定義使用本身的aop
CGLIB動態代理技術 有時候你會發現 你的配置和我同樣,可是aop沒有生效,這頗有多是SpringMVC的配置的代理模式不對。
方法裏的xxxService對象若是使用autowared注入,沒法啓動aspect, 可是 xxxService = ctx.getBean("xxxxx")獲取,是能夠啓用aspect的
這個時候 xxxService 並非注入進來的,即便有 @Autowired 註解,這時的註解沒有任何做用。 只有 Spring 生成的對象纔有 AOP 功能,由於 Spring 生成的代理對象纔有 AOP 功能。
配置spring.aop.proxy-target-class=true
/** * Created by chen on 2017/10/27. * <p> * Email 122741482@qq.com * <p> * Describe: */ @Service public class JoinpointTest { public void JoinpointTest(){ System.out.println("**********JoinpointTest*****************"); } public void test(){ System.out.println("JoinpointTest++++執行我正常流水線的業務邏輯"); } }
@Aspect // FOR AOP @Order(-99) // 控制多個Aspect的執行順序,越小越先執行 @Component public class AdviceTest { @Pointcut(value="execution(* com.slife.java8.aspect.AspectTest.test())") public void poincut(){ } @Before("poincut()") public void beforeTest() { System.out.println("執行 方法 以前 調用----"); } @After("execution(* com.slife.java8.aspect.AspectTest.test())") public void afterTest() { System.out.println(); System.out.println("執行 方法 以後 調用----"); } @Around("execution(* com.slife.java8.aspect.AspectTest.test())") public void aroundTest() { System.out.println(); System.out.println("執行 方法 先後 調用----"); } @AfterReturning("execution(* com.slife.java8.aspect.AspectTest.test())") public void afterReturningTest() { System.out.println(); System.out.println("執行 方法 AfterReturning 調用----"); } @AfterThrowing("execution(* com.slife.java8.aspect.AspectTest.test())") public void afterThrowingTest() { System.out.println(); System.out.println("執行 方法 AfterThrowing 調用----"); } @Before("execution(* com.slife.java8..*test*(..))") public void aspecttest1() { System.out.println(); System.out.println("執行 方法aspecttest1 Before 調用----"); } }
個人官網
個人官網http://guan2ye.com 個人CSDN地址http://blog.csdn.net/chenjianandiyi 個人簡書地址http://www.jianshu.com/u/9b5d1921ce34 個人githubhttps://github.com/javanan 個人碼雲地址https://gitee.com/jamen/ 點擊獲取阿里雲優惠券https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=vf2b5zld&utm_source=vf2b5zld