記錄,備忘……
使用實例:
package test.aop;
public class Test {
/**
*
* 使用spring的aop切面實現日誌記錄
* 1 aop開啓springboot: spring.aop.auto=true
* 2 日誌註解
* 3 切面類
*
* 註解使用實例
*/
@SysLog(operationType = "新增",description = "新增用戶")
public void addSomeThing(){
// doSomeThing……
}
}
日誌註解:
package test.aop;
import java.lang.annotation.*;
/**
* 系統日誌註解
*
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
/**
* 要執行的操作類型比如:add操作
**/
String operationType() default "";
/**
* 要執行的具體操作比如:添加用戶
**/
String description() default "";
}
切面類:
package test.aop;
import cn.hutool.extra.servlet.ServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;
/**
* 日誌切點類
* 通知:advice(前置,後置,環繞)
*
*/
@Slf4j
@Aspect
//@Order(value=6) // 多個切面時,使用order註解來進行設置順序,值越小優先級越高
@Component
public class SysLogAspect {
/**
* 切點:配置切點表達式
* execution(* test.*.*(..))代表test包下所有類的所有方法都會被代理
*/
@Pointcut("@annotation(test.aop.SysLog)")
public void logAspect() {
}
/**
* 返回通知:方法返回時調用
*/
@AfterReturning(value = "logAspect() && @annotation(sysLog)")
public void around(JoinPoint point, SysLog sysLog) {
// request請求對象
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//攔截的類名,如某個serviceImpl
Class clazz = point.getTarget().getClass();
//攔截的方法
Method method = ((MethodSignature) point.getSignature()).getMethod();
// 獲取request請求參數
Map<String, String> parameterMap = ServletUtil.getParamMap(request);
// 業務處理:存儲日誌數據……
}
/**
* 前置通知:目標方法執行前執行
*/
@Before(value="logAspect()")
public void before(JoinPoint joinPoint){
System.out.println("目標方法名爲:" + joinPoint.getSignature().getName());
System.out.println("目標方法所屬類的簡單類名:" + joinPoint.getSignature().getDeclaringType().getSimpleName());
System.out.println("目標方法所屬類的類名:" + joinPoint.getSignature().getDeclaringTypeName());
System.out.println("目標方法聲明類型:" + Modifier.toString(joinPoint.getSignature().getModifiers()));
//獲取傳入目標方法的參數
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
System.out.println("第" + (i+1) + "個參數爲:" + args[i]);
}
System.out.println("被代理的對象:" + joinPoint.getTarget());
System.out.println("代理對象自己:" + joinPoint.getThis());
/*
執行結果:
目標方法名爲:getMethod
目標方法所屬類的簡單類名:TestController
目標方法所屬類的類名:test.aop.ClientController
目標方法聲明類型:public
// 此處參數即賦值後的形參
第1個參數爲:
第2個參數爲:
被代理的對象:test.aop.ClientController@30c3876b
代理對象自己:test.aop.ClientController@30c3876b
*/
}
/**
* 後置通知:目標方法執行後執行
*/
@After(value="logAspect()")
public void after(JoinPoint joinPoint){
}
/**
* 異常通知:目標方法異常時執行
*/
@AfterThrowing(value="logAspect()")
public void exeException(JoinPoint joinPoint){
}
/**
* 環繞通知:自定義方法的執行時機。
*
* ProceedingJoinPoint對象是JoinPoint的子接口,該對象只用在@Around的切面方法中,
* Object proceed() throws Throwable //執行目標方法
* Object proceed(Object[] var1) throws Throwable //傳入的新的參數去執行目標方法
*
* 方法返回值必須返回,因爲環繞通知相當於代理動作。此時方法返回值即視爲目標方法返回值
*/
@Around(value="logAspect()")
public Object aroundMethod(ProceedingJoinPoint joinPoint){
//
System.out.println("方法執行前處理……");
// 執行目標方法
Object result = joinPoint.proeed();
//
System.out.println("方法執行後處理……");
return result;
}
}