Spring提供了一個AOP框架,讓我把切麵插入到方法執行的周圍。 1、概念 定義通用功能,通過申明定義這些功能要以何種方式在何處應用,而不需要修改受影響的類。這些通用功能可以模塊化為特殊的類,即切麵。 連接點:連接點是一個應用執行過程中能夠插入一個切麵的點(Spring只支持方法級別的連接點) 切 ...
Spring提供了一個AOP框架,讓我把切麵插入到方法執行的周圍。
1、概念
定義通用功能,通過申明定義這些功能要以何種方式在何處應用,而不需要修改受影響的類。這些通用功能可以模塊化為特殊的類,即切麵。
- 連接點:連接點是一個應用執行過程中能夠插入一個切麵的點(Spring只支持方法級別的連接點)
- 切點:定義匹配通知織入的一個或多個連接點(在哪做)
- 通知:切麵的工作(做什麼)
- 切麵:由切點和通知的結合
- 織入:把切麵應用到目標對象並創建新的代理對象的過程
通知分類
- 前置通知:在目標方法調用之前執行
- 後置通知:在目標方法執行之後執行,不管是正常執行還是拋了異常
- 返回通知:在目標方法執行成功後執行,不管方法是否有返回值
- 異常通知:在目標方法拋出異常後調用
- 環繞通知:通知方法將目標方法封裝起來,可以達到前幾種通知的效果
2、Spring切麵編程分為:基於註解和基於XML配置形式
- 基於註解形式
首先開啟Aspect代理功能
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
定義切麵,並將該bean交給spring管理
package com.cn.pojo; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Component @Aspect public class Audience { @Pointcut("execution(* com.cn.pojo.Performance.*(..))") public void performance(){} @Before("performance()") public void takeSeats(){ System.out.println( "Before:take seats!"); } @After("performance()") public void goHome(){ System.out.println("After:go home!"); } @AfterReturning(value = "performance()", returning = "result") public void applause(JoinPoint joinPoint,Object result){ System.out.println("AfterReturning:clap clap clap!"); System.out.println("AfterReturning:"+joinPoint.getArgs()[0]); System.out.println("AfterReturning:applause-當前在場人數:"+result); } @AfterThrowing(value = "performance()", throwing = "ex") public void demandRefund(JoinPoint joinPoint, Exception ex){ System.out.println("AfterThrowing:demanding a refund!"); System.out.println("AfterThrowing:"+joinPoint.getArgs()[0]); System.out.println("AfterThrowing:異常信息為 "+ex.getMessage()); } @Around("performance()") public Object all(ProceedingJoinPoint proceedingJoinPoint){ try{ System.out.println("Around:執行perform方法-前置通知"); Object obj=proceedingJoinPoint.proceed(new Object[]{189}); System.out.println("Around:執行perform方法-返回通知"); return obj; }catch (Throwable throwable) { System.out.println("Around:執行perform方法-異常通知"); return -1; }finally { System.out.println("Around:執行perform方法---後置通知"); } } }
除了execution外,還有以下指示器用於定義切點:
方法入參切點函數 | args() | 類名 | 通過判別目標類方法運行時入參對象的類型定義指定連接點。如args(com.baobaotao.Waiter)表示所有有且僅有一個按類型匹配於Waiter的入參的方法。 |
@args() | 類型註 解類名 | 通過判別目標方法的運行時入參對象的類是否標註特定註解來指定連接點。如@args(com.baobaotao.Monitorable)表示任何這樣的一個目標方法:它有一個入參且入參對象的類標註@Monitorable註解。 | |
目標類切點函數 | within() | 類名匹配串 | 表示特定域下的所有連接點。如within(com.baobaotao.service.*)表示com.baobaotao.service包中的所有連接點,也即包中所有類的所有方法,而within(com.baobaotao.service.*Service)表示在com.baobaotao.service包中,所有以Service結尾的類的所有連接點。 |
target() | 類名 | 假如目標類按類型匹配於指定類,則目標類的所有連接點匹配這個切點。如通過target(com.baobaotao.Waiter)定義的切點,Waiter、以及Waiter實現類NaiveWaiter中所有連接點都匹配該切點。 | |
@within() | 類型註解類名 | 假如目標類按類型匹配於某個類A,且類A標註了特定註解,則目標類的所有連接點匹配這個切點。 如@within(com.baobaotao.Monitorable)定義的切點,假如Waiter類標註了@Monitorable註解,則Waiter以及Waiter實現類NaiveWaiter類的所有連接點都匹配。 | |
@target() | 類型註解類名 | 目標類標註了特定註解,則目標類所有連接點匹配該切點。如@target(com.baobaotao.Monitorable),假如NaiveWaiter標註了@Monitorable,則NaiveWaiter所有連接點匹配切點。 |
- 基於XML方式
定義POJO
package com.cn.pojo; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; public class Audience { public void takeSeats(){ System.out.println( "Before:take seats!"); } public void goHome(){ System.out.println("After:go home!"); } public void applause(JoinPoint joinPoint,Object result){ System.out.println("AfterReturning:clap clap clap!"); } public void demandRefund(JoinPoint joinPoint, Exception ex){ System.out.println("AfterThrowing:demanding a refund!"); } public Object all(ProceedingJoinPoint proceedingJoinPoint){ try{ System.out.println("Around:執行perform方法-前置通知"); Object obj=proceedingJoinPoint.proceed(new Object[]{189}); System.out.println("Around:執行perform方法-返回通知"); return obj; }catch (Throwable throwable) { System.out.println("Around:執行perform方法-異常通知"); return -1; }finally { System.out.println("Around:執行perform方法---後置通知"); } } }
將POJO申明為切麵,並交spring管理
<aop:config> <aop:aspect ref="audience"> <aop:pointcut id="perform" expression="execution(* com.cn.pojo.Performance.*(..))"></aop:pointcut> <aop:before method="takeSeats" pointcut-ref="perform"></aop:before> <aop:after method="goHome" pointcut-ref="perform"></aop:after> <aop:after-returning method="applause" pointcut-ref="perform" returning="result"></aop:after-returning> <aop:after-throwing method="demandRefund" pointcut-ref="perform" throwing="ex"></aop:after-throwing> <aop:around method="all" pointcut-ref="perform"></aop:around> </aop:aspect> </aop:config>