Spring的AOP實現日誌記錄

記錄,備忘……

使用實例:

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;
    }




}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章