1. 程式人生 > 實用技巧 >spring學習(四)AOP

spring學習(四)AOP

cglib代理

動態代理有個約束:目標物件一定是要有介面的,沒有介面就不能實現動態代理…..----->因此出現了cglib代理

cglib代理也叫子類代理,從記憶體中構建出一個子類來擴充套件目標物件的功能!

  • CGLIB是一個強大的高效能的程式碼生成包,它可以在執行期擴充套件Java類與實現Java介面。它廣泛的被許多AOP的框架使用,例如Spring AOP和dynaop,為他們提供方法的interception(攔截)

寫cglib代理步驟:

  • 需要引入cglib – jar檔案, 但是spring的核心包中已經包括了cglib功能,所以直接引入spring-core-3.2.5.jar即可。

  • 引入功能包後,就可以在記憶體中動態構建子類

  • 代理的類不能為final,否則報錯【在記憶體中構建子類來做擴充套件,當然不能為final,有final就不能繼承了】

  • 目標物件的方法如果為final/static, 那麼就不會被攔截,即不會執行目標物件額外的業務方法。

AOP

Aop: aspect object programming 面向切面程式設計

  • 功能: 讓關注點程式碼(重複程式碼)與業務程式碼分離!

  • 面向切面程式設計就是指: 對很多功能都有的重複的程式碼抽取,再在執行的時候往業務方法上動態植入“切面類程式碼”。

步驟:

  • 1、引入aop相關jar檔案 (aspectj aop優秀元件)

    • spring-aop-3.2.5.RELEASE.jar 【spring3.2原始碼】

    • aopalliance.jar 【spring2.5原始碼/lib/aopalliance】

    • aspectjweaver.jar 【spring2.5原始碼/lib/aspectj】或【aspectj-1.8.2\lib】

    • aspectjrt.jar 【spring2.5原始碼/lib/aspectj】或【aspectj-1.8.2\lib】

  • 2、bean.xml中引入aop宣告

<beans
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
</beans>

註解:

  • @Aspect 指定一個類為切面類

  • @Pointcut("execution(* cn.itcast.e_aop_anno.*.*(..))") 指定切入點表示式

    • Pointcut定義時,還可以使用&&、||、! 這三個運算

    @Pointcut("logSender() || logReceiver()")
    private void logMessage(){}
    • 還可以將一些公用的Pointcut放到一個類中,以供整個應用程式使用,在使用時,指定完整的類名加上Pointcut簽名就可以了

    @Before("bean.Pointcuts.logMessage()")
    public void before() {
    }
  • @Before("pointCut_()") 前置通知: 目標方法之前執行

  • @After("pointCut_()") 後置通知:目標方法之後執行(始終執行)

  • @AfterReturning("pointCut_()") 返回後通知: 執行方法結束前執行(異常不執行)

  • @AfterThrowing("pointCut_()") 異常通知: 出現異常時候執行

  • @Around("pointCut_()") 環繞通知: 環繞目標方法執行,使用該註解的方法必須傳入ProceedingJoinPoint物件,並呼叫它的proceed()方法(執行目標方法)

@Pointcut表示式解析 execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)

括號中各個pattern分別表示:

  • 修飾符匹配(modifier-pattern?),可省略不寫

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

  • 類路徑匹配(declaring-type-pattern?),bean.* 表示bean包下的所有類

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

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

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

  • 其中後面跟著“?”的是可選項

@Component
@Aspect
public class AOP {
//定義切入點
@Pointcut("execution(* bean.*.*(..))")
public void pt(){}

//可以直接寫切入點表示式
@Before("execution(* bean.*.*(..))")
public void before(){
System.out.println("開始事務");
}
//使用定義好的切入點
@After("pt()")
public void after(){
System.out.println("關閉事務");
}

@Around("pt()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("環繞前...");
//必須傳入ProceedingJoinPoint物件,呼叫proceed()方法 來執行目標方法
joinPoint.proceed();
System.out.println("環繞後...");
}
}