AOP主要用於日誌記錄,性能統計,安全控制(權限控制),事務處理,異常處理等。將日誌記錄,性能統計,安全控制,事務處理,異常處理等代碼從業務邏輯代碼中劃分出來,經過對這些行爲的分離,咱們但願能夠將它們獨立到非指導業務邏輯的方法中,進而改變這些行爲的時候不影響業務邏輯的代碼。
Spring AOP織入加強(Advice)的方式有兩種 若是鏈接點實現了接口採用jdk自帶的動態代理的形式實現織入,若是鏈接點沒有實現接口則採用動態字節碼生成技術(CGLIB)實現織入。git
加強程序執行的某個特定位置(要在哪一個地方作加強操做)。Spring僅支持方法的鏈接點,既僅能在方法調用前,方法調用後,方法拋出異常時等這些程序執行點進行織入加強。github
切點是一組鏈接點的集合。AOP經過「切點」定位特定的鏈接點。經過數據庫查詢的概念來理解切點和鏈接點的關係再適合不過了:鏈接點至關於數據庫中的記錄,而切點至關於查詢條件。正則表達式
加強是織入到目標類鏈接點上的一段程序代碼。表示要在鏈接點上作的操做。spring
切面由切點和加強(引介)組成(能夠包含多個切點和多個加強),它既包括了橫切邏輯的定義,也包括了鏈接點的定義,SpringAOP就是負責實施切面的框架,它將切面所定義的橫切邏輯織入到切面所指定的連接點中。數據庫
@Aspect public class LogAspect { @Pointcut("execution(* com.ctj.service.*.*(..))") public void pointcutName(){} @Before("pointcutName()") public void performance(){ System.out.println("Spring AOP"); } }
咱們如何在定義切點(Pointcut)的時候指定一類Joinpoint呢?有兩種方式 簡單的方法名指定以及正則表達式兩種方式。編程
Spring AOP僅支持方法執行類型的Joinpoint 因此execution將會是咱們用的最多的標誌符,用它來幫咱們匹配擁有指定方法前面的Joinpoint。匹配規則以下:
execution(modifiers-pattern? return-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern)安全
方法的返回類型 方法名及參數部分的匹配模式是必須指定的 其餘部分能夠省略。
咱們還能夠在表達式中使用兩種通配符:*和..
第一:*能夠用於任何部分的匹配模式中,匹配相鄰的多個字符,即一個Work 。若是放在了方法參數的位置標示參數是任何類型的。
例如:execution(* *(String))
第二:..通配符能夠在兩個位置使用 一個是declaring-type-pattern的位置,一個是在方法參數匹配模式的位置。
若是是放在了方法類型的位置,能夠指定多個層次的類型聲明。例如:
execution(void cn.spring.*.doSomething(*)) 指定到cn.spring下的全部類型。
若是是放在了方法參數的匹配位置,則表示該方法能夠有0到多個參數。例如:
execution(void *.doSomething(..))框架
within標誌符只接受類型聲明,它將匹配指定類型下全部的Joinpoint。
例如:within(cn.spring.aop.target.*) 將會匹配 cn.spring.aop.target包下全部類型的方法級別的Joinpoint。性能
使用@annotation標誌符會檢查系統中全部對象的全部方法級別Joinpoint,若是被檢測的方法標註有@annotation標誌符所指定的註解類型,那麼當前方法所在的Joinpoint將被Pointcut表達式匹配。例如:@pointcut("@annotation(com.test.aop.log.ALog)") 匹配全部使用了ALog註解的方法。spa
匹配表達式的維度有不少 上面只是一小部分經常使用的,而且這些維度是能夠組合的 使用||或者$$等等
例如:@around("within(com.test.finance..*) && @annotation(com.test.finance.platform.intf.base.db.ReadOnly)")
在定義Advice的時候 咱們匹配的維度能夠直接寫定義有@pointcut的方法名稱 也能夠直接使用定義@joinpoint的那一套東西來直接定義要在哪些地方織入(能夠直接在Advice上指定匹配哪些方法)
定義完切面以後咱們要在spring中註冊這個切面類,爲了讓spring能自動幫咱們實現織入 咱們還須要開啓自動注入 在spring配置文件中:<aop:aspectj-autoproxy proxy-target-class="true"/> 這樣spring就能在IOC容器找到全部要織入的方法 動態幫咱們織入。
業務類代碼:
package com.ctj.service; import org.springframework.stereotype.Service; @Service public class BusinessService { public void say(){ System.out.println("Business Code"); } }
切面類定義:
package com.ctj.aspect; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect public class LogAspect { @Pointcut("execution(* com.ctj.service.*.*(..))") public void pointcutName(){} @Before("pointcutName()") public void performance(){ System.out.println("Spring AOP"); } }
spring-aop.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" 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-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd"> <aop:aspectj-autoproxy proxy-target-class="true"/> <bean id="logAspect" class="com.ctj.aspect.LogAspect"> </bean> </beans>
基於註解的Spring AOP須要JDK1.5版本之後才能使用,以前的版本須要使用基於Schema也就是配置文件的形式來實現,若是jdk版本高的話 建議仍是使用註解的形式。