Spring AOP – 使用 Aspectj
使用 Aspectj 註解實現各種通知
@Before:前置通知,在方法執行前執行
@After:後置通知,在方法執行後通知
@AfterRunning:返回通知,在方法返回結果後通知
@AfterThrowing:異常通知:在方法拋出異常後通知
@Around:環繞通知:圍繞着方法執行
需要以下jar包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectjrt.version}</version>
</dependency>
創建接口與實現類,並交給 Spring 管理
public interface ArithmeticCalculator {
int add(int i, int j);
int div(int i, int j);
}
@Component
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
int result = i + j;
System.out.println("result:" + result);
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
System.out.println("result:" + result);
return result;
}
}
在Spirng配置里加入:
<!-- 配置自動掃描的包 -->
<context:component-scan base-package="com.java.spring.aop"></context:component-scan>
使用 Aspectj 註解來實現前置通知
//把該類聲明爲一個切面:需要先將類放入到 IOC 容器中 ,再聲明爲一個切面
@Aspect
@Component
public class Logging {
/*
聲明該方法是一個 前置通知:在目標方法開始前執行
execution(* com.java.spring.aop.impl.*.*()) 中表示任意修飾符,任意返回值,
在com.java.spring.aop.impl 包下任意類中的任意方法
*/
@Before("execution(* com.java.spring.aop.impl.*.*(int,int))")
//可以在方法裏聲明類型爲 JoinPoint 的參數,獲得連接點的細節,如方法名稱和參數值
public void beforLogin(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName(); //獲取方法名稱
List<Object> args = Arrays.asList(joinPoint.getArgs()); //獲取方法參數值
System.out.println("method " + methodName + " begins " + args);
}
}
執行結果如下
method add begins [3, 6]
result:9
method div begins [12, 3]
result:4
使用 Aspectj 註解來實現後置通知
//在方法執行後,執行通知(無論是否發送異常)
@After("execution(* com.java.spring.aop.impl.*.*(int,int))")
public void afterLogin(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("method " + methodName);
}
執行結果如下
result:9
method add end
result:4
method div end
注意:即便發生異常,依然會執行:
使用 Aspectj 註解來實現返回通知
//在方法正常結束後執行,可以訪問到方法的返回值
@AfterReturning(value = "execution(* com.java.spring.aop.impl.*.*(int,int))",returning = "result")
public void afterReturningLogin(JoinPoint joinPoint , Object result){
String methodName = joinPoint.getSignature().getName();
System.out.println("method " + methodName+" result " + result);
}
執行結果如下
result:9
method add result 9
result:4
method div result 4
使用 Aspectj 註解來實現異常通知
//在方法出現異常時執行,可以訪問到異常對象,且可以指定特定異常在執行通知
@AfterThrowing(value = "execution(* com.java.spring.aop.impl.*.*(int,int))",throwing = "ex")
public void afterThrowingLogin(JoinPoint joinPoint , Exception ex){
String methodName = joinPoint.getSignature().getName();
System.out.println("method " + methodName+" exception " + ex);
}
執行結果如下
使用 Aspectj 註解來實現環繞通知
/*
環繞通知需要有 ProceedingJoinPoint 這個參數,這個參數可以決定是否執行目標方法
環繞通知必須有返回值,返回值爲目標方法返回值
*/
@Around("execution(* com.java.spring.aop.impl.*.*(int,int))")
public Object aroundLogin(ProceedingJoinPoint pjd ){
Object result = null;
String methodName = pjd.getSignature().getName();
try {
//前置通知
System.out.println("method " + methodName + " begins " + Arrays.asList(pjd.getArgs()));
//執行目標方法
result = pjd.proceed();
//返回通知
System.out.println("method " + methodName+" result " + result);
} catch (Throwable e) {
//異常通知
System.out.println("method " + methodName+" exception " + e);
}
//後置通知
System.out.println("method " + methodName+" end ");
return result;
}
執行結果如下
發生異常後如下