https://www.cnblogs.com/qinglangyijiu/p/8425653.html
spingmvc配置AOP有兩種方式,一種是利用注解的方式配置,另一種是XML配置實現。
應用注解的方式配置:
先在maven中引入AOP用到的依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.1.RELEASE</version>
</dependency>
<!-- aop aspect注解導包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
然后在springmvc的配置文件中加入AOP的配置,即掃描AOP的包以及讓AOP生效
<!-- AOP 注解方式 ;定義Aspect -->
<!-- 激活組件掃描功能,在包"com.example.aop及其子包下面自動掃描通過注解配置的組件-->
<context:component-scan base-package="com.example.aop"/>
<!-- 啟動AspectJ支持 只對掃描過的bean有效-->
<aop:aspectj-autoproxy proxy-target-class="true" />
然后加入AOP邏輯處理類
package com.example.aop;
import java.util.Arrays;
import java.util.List;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Aspect //該標簽把LoggerAspect類聲明為一個切面
@Order(1) //設置切面的優先級:如果有多個切面,可通過設置優先級控制切面的執行順序(數值越小,優先級越高)
@Component //該標簽把LoggerAspect類放到IOC容器中
public class LoggerAspect {
/**
* 定義一個方法,用於聲明切入點表達式,方法中一般不需要添加其他代碼
* 使用@Pointcut聲明切入點表達式
* 后面的通知直接使用方法名來引用當前的切點表達式;如果是其他類使用,加上包名即可
*/
@Pointcut("execution(public * com.example.controller.*Controller.*(..))")
public void declearJoinPointExpression(){}
/**
* 前置通知
* @param joinPoint
*/
@Before("declearJoinPointExpression()") //該標簽聲明次方法是一個前置通知:在目標方法開始之前執行
public void beforMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("this method "+methodName+" begin. param<"+ args+">");
}
/**
* 后置通知(無論方法是否發生異常都會執行,所以訪問不到方法的返回值)
* @param joinPoint
*/
@After("declearJoinPointExpression()")
public void afterMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("this method "+methodName+" end.");
}
/**
* 返回通知(在方法正常結束執行的代碼)
* 返回通知可以訪問到方法的返回值!
* @param joinPoint
*/
@AfterReturning(value="declearJoinPointExpression()",returning="result")
public void afterReturnMethod(JoinPoint joinPoint,Object result){
String methodName = joinPoint.getSignature().getName();
System.out.println("this method "+methodName+" end.result<"+result+">");
}
/**
* 異常通知(方法發生異常執行的代碼)
* 可以訪問到異常對象;且可以指定在出現特定異常時執行的代碼
* @param joinPoint
* @param ex
*/
@AfterThrowing(value="declearJoinPointExpression()",throwing="ex")
public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){
String methodName = joinPoint.getSignature().getName();
System.out.println("this method "+methodName+" end.ex message<"+ex+">");
}
/**
* 環繞通知(需要攜帶類型為ProceedingJoinPoint類型的參數)
* 環繞通知包含前置、后置、返回、異常通知;ProceedingJoinPoin 類型的參數可以決定是否執行目標方法
* 且環繞通知必須有返回值,返回值即目標方法的返回值
* @param point
*/
@Around(value="declearJoinPointExpression()")
public Object aroundMethod(ProceedingJoinPoint point){
Object result = null;
String methodName = point.getSignature().getName();
try {
//前置通知
System.out.println("The method "+ methodName+" start. param<"+ Arrays.asList(point.getArgs())+">");
//執行目標方法
result = point.proceed();
//返回通知
System.out.println("The method "+ methodName+" end. result<"+ result+">");
} catch (Throwable e) {
//異常通知
System.out.println("this method "+methodName+" end.ex message<"+e+">");
throw new RuntimeException(e);
}
//后置通知
System.out.println("The method "+ methodName+" end.");
return result;
}
}
在類上加上注解Aspect聲明這個類是一個切面,加上component注解加入IOC容器中。Order注解是優先級,如果只有一個切面類可以不用。注解pointcut是聲明注解的作用范圍。execution(public * com.example.controller.*Controller.*(..))我這里用的execution表達式,代表作用com.example.controller包下所有以Controller結尾類的所有Public方法。@pointcut所描述的方法里面通常不需要內容。切面通知包含:
前置通知(@Before,在執行方法之前,參數為JoinPoint)
后置通知(@After,無論方法拋不拋異常都會執行,所以獲取不到方法的返回值。參數為JoinPoint)
返回通知(@AfterReturning,在方法正常結束后執行,可以獲取到方法的返回值。參數為JoinPoint和result(Object))
異常通知(@AfterThrowing,在方法拋出異常時執行,可以獲取到異常對象,且可以指定在出現特定異常時執行的代碼,參數為JoinPoint何Exception)
環繞通知(@Around,環繞通知需要攜帶的類型為ProceedingJoinPoint類型的參數, 環繞通知包含前置、后置、返回、異常通知;ProceedingJoinPoin 類型的參數可以決定是否執行目標方法,且環繞通知必須有返回值,返回值即目標方法的返回值)
應用XML方式配置
依賴的話,應該不用加入AOP注解的依賴。先定義一個類,作為切面類。
package com.example.aop;
import java.util.Arrays;
import java.util.List;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;
@Component //該標簽把LoggerAspect類放到IOC容器中
public class SysAspect {
/**
* 前置通知
* @param joinPoint
*/
public void beforMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("this method "+methodName+" begin. param<"+ args+">");
}
/**
* 后置通知(無論方法是否發生異常都會執行,所以訪問不到方法的返回值)
* @param joinPoint
*/
public void afterMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("this method "+methodName+" end.");
}
/**
* 返回通知(在方法正常結束執行的代碼)
* 返回通知可以訪問到方法的返回值!
* @param joinPoint
*/
public void afterReturnMethod(JoinPoint joinPoint,Object result){
String methodName = joinPoint.getSignature().getName();
System.out.println("this method "+methodName+" end.result<"+result+">");
}
/**
* 異常通知(方法發生異常執行的代碼)
* 可以訪問到異常對象;且可以指定在出現特定異常時執行的代碼
* @param joinPoint
* @param ex
*/
public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){
String methodName = joinPoint.getSignature().getName();
System.out.println("this method "+methodName+" end.ex message<"+ex+">");
}
/**
* 環繞通知(需要攜帶類型為ProceedingJoinPoint類型的參數)
* 環繞通知包含前置、后置、返回、異常通知;ProceedingJoinPoin 類型的參數可以決定是否執行目標方法
* 且環繞通知必須有返回值,返回值即目標方法的返回值
* @param point
*/
public Object aroundMethod(ProceedingJoinPoint point){
Object result = null;
String methodName = point.getSignature().getName();
try {
//前置通知
System.out.println("The method "+ methodName+" start. param<"+ Arrays.asList(point.getArgs())+">");
//執行目標方法
result = point.proceed();
//返回通知
System.out.println("The method "+ methodName+" end. result<"+ result+">");
} catch (Throwable e) {
//異常通知
System.out.println("this method "+methodName+" end.ex message<"+e+">");
throw new RuntimeException(e);
}
//后置通知
System.out.println("The method "+ methodName+" end.");
return result;
}
}
可以看到,這個類除了沒有@Aspect以及相關切面的注解外,跟正常的AOP切面類沒有差別。如果聲明其讓其為一個切面。需要我們在xml文件中手動配置。
<!-- 配置切面的Bean -->
<bean id="sysAspect" class="com.example.aop.SysAspect"/>
<!-- 配置AOP -->
<aop:config>
<!-- 配置切點表達式 -->
<aop:pointcut id="pointcut" expression="execution(public * com.example.controller.*Controller.*(..))"/>
<!-- 配置切面及配置 -->
<aop:aspect order="3" ref="sysAspect">
<!-- 前置通知 -->
<aop:before method="beforMethod" pointcut-ref="pointcut" />
<!-- 后置通知 -->
<aop:after method="afterMethod" pointcut-ref="pointcut"/>
<!-- 返回通知 -->
<aop:after-returning method="afterReturnMethod" pointcut-ref="pointcut" returning="result"/>
<!-- 異常通知 -->
<aop:after-throwing method="afterThrowingMethod" pointcut-ref="pointcut" throwing="ex"/>
<aop:around method="aroundMethod" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
定義的切面bean就是我們自定義的切面類,然后配置AOP(<aop:config>)。先定義切面范圍pointcut。余下的就是制定aop的切面類、優先級然后再詳細配置切面的通知。這樣就跟注解的方式產生的效果一致了。

