AOP(Aspect-Oriented Programming):面向切面編程,是對傳統OOP(面向對象編程)的補充。
AOP主要編程對象是切面(aspect),而切面模塊化橫切關注點
在應用AOP編程時,需要定義公共功能,但可以明確定義這個功能在哪裏,以什麼方式應用,並且不必須改受影響的類,這樣橫切關注點就被模塊化到特殊的對象(切面)裏。
AOP的好處:
每個事物邏輯位於一個位置,代碼不分散,便於維護和升級
業務模塊更簡潔,只包含核心業務代碼
AOP術語:
切面(Aspect):橫切關注點(跨越應用程序多個模塊的功能)被模塊化到特殊的對象
通知(Advice):切面必須完成的工作
目標(Target):被通知的對象
代理(Proxy):向目標對象應用通知之後創建的對象
連接點(JoinPoint):程序執行的某個特定位置,如類某個方法調用前、調用後、方法拋出異常後等。連接點由兩個信息確定:方法表示的程序執行點相對點表示的方位。
切點(pointcut):每個類都有多個連接點,即連接點是程序中客觀存在的事務。AOP通過切點定位到特殊的連接點。切點和連接點不是一對一的關係,一個切點匹配多個連接點,切點通過org.springframwork.aop.Pointcut接口進行描述,使用類和方法作爲連接點的查詢條件。
AspctJ: AOP框架,可以使用基於AspectJ註解或基於XML配置AOP
AspectJ支持5種類型的通知:
@Before 前置通知
@After 後置通知,無論該方法是否出現異常,訪問不到方法的返回值
@AfterReturning 返回通知,在方法返回結果後執行,可以訪問到方法的返回值
@AfterThrowing 異常通知,在方法拋出異常後執行
@Around 環繞通知
利用方法簽名編寫AspectJ切入點表達式
execution * spring.aop.CalculatorIml.*(…)
第一個代表任意修飾符和返回值,第二個代表任意方法,”…”匹配任意數量參數
要聲明Aspectj切面,需要在IOC容器中將切面聲明爲bean實例
切面類:
@Aspect
@Component
public class LogginAspect {
//聲明該方法是前置通知,在目標方法執行之前執行
@Before("execution(public int spring.aop.CalculatorIml.add(int, int))")
public void before() {
System.out.println("before");
}
}
還需要配置:
<!-- 使Aspectj註解起作用,自動爲匹配類生產代理 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
返回通知:
@AfterReturning(value="execution(public int spring.aop.CalculatorIml.add(int, int))",
returning="result")
public void Returning(int result) {
System.out.println("returning :" + result);
}
異常通知:
@AfterThrowing(value="execution(public double spring.aop.CalculatorIml.chu(int, int))",
throwing="ex")
public void Throwing(Exception ex) {
System.out.println("ex");
System.out.println("throwing :" +ex );
}
//目標類try/catch異常後異常通知接收不到
切面的重用切點表達式
使用Pointcut來聲明切入點表達式
定義一個方法,用於聲明切入點表達式,一般的,該方法中不再需要添加其他代碼:
@Pointcut("execution(public int spring.aop.CalculatorIml.add(int, int))")
public void JoinPointExpression() {}
//聲明該方法是前置通知,在目標方法執行之前執行
@Before("JoinPointExpression()")
public void before() {
System.out.println("before");
}
XML配置文件方式配置AOP:
<bean id="calculator" class="spring.aop.CalculatorIml"></bean>
<bean id="loggion" class="spring.aop.LogginAspect"></bean>
<!-- 配置AOP -->
<aop:config>
<!-- 配置切點表達式 -->
<aop:pointcut expression="execution(public int spring.aop.CalculatorIml.add(int, int))" id="beforePoint"/>
<!-- 配置切面及通知 -->
<aop:aspect ref="loggion" order="1">
<!-- 修改aop:before 元素標籤實現不同的通知 -->
<aop:before method="before" pointcut-ref="beforePoint"/>
</aop:aspect>
</aop:config>