SpringBoot@Aspect 打印訪問請求和返回數據方式

SpringBoot@Aspect 打印訪問請求和返回數據

為什麼要用aspect, 使用aspect 可以使記錄日志的功能面向切面,這樣可以降低代碼的耦合性。提供瞭兩種方式對輸入輸出的數據進行打日志,如下:

aspect:第一種方式

@Before 和 @AfterReturning 來對 controller 進行切面。

輸出數據:

aspect:第二種方式

@Around 來對controller 進行切面。

輸出數據:

兩種方法都是能夠對請求數據做日志監控。

第一種方式和第二種方式有一些不同,第二種方式使用的是@Around 環繞的方式去做的處理,joinPoint.proceed()返回數據需要等方法執行完才能執行下面的代碼,這種是阻塞式的請求,所以個人建議還是采用第一種方法比較合適。

SpringBoot @Aspect註解詳情

1、添加maven依賴註解

        <!--springBoot的aop-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2、添加AOP類

@Component
@Aspect
public class JournalServiceAspect {
}

3、設置切面點

    /**切面點*/
    private final String POINT_CUT = "execution(* com.xx.xx..*(..))";
    @Pointcut(POINT_CUT)
    private void pointcut(){}

4、配置前置通知

/** 
 * 前置通知,方法調用前被調用 
 * @param joinPoint 
 */  
@Before(value = POINT_CUT)
public void before(JoinPoint joinPoint){
    logger.info("前置通知");
    //獲取目標方法的參數信息  
    Object[] obj = joinPoint.getArgs();  
    //AOP代理類的信息  
    joinPoint.getThis();  
    //代理的目標對象  
    joinPoint.getTarget();  
    //用的最多 通知的簽名  
    Signature signature = joinPoint.getSignature();  
    //代理的是哪一個方法  
    logger.info("代理的是哪一個方法"+signature.getName());  
    //AOP代理類的名字  
    logger.info("AOP代理類的名字"+signature.getDeclaringTypeName());  
    //AOP代理類的類(class)信息  
    signature.getDeclaringType();  
    //獲取RequestAttributes  
    RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();  
    //從獲取RequestAttributes中獲取HttpServletRequest的信息  
    HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);  
    //如果要獲取Session信息的話,可以這樣寫:  
    //HttpSession session = (HttpSession) requestAttributes.resolveReference(RequestAttributes.REFERENCE_SESSION);  
    //獲取請求參數
    Enumeration<String> enumeration = request.getParameterNames();  
    Map<String,String> parameterMap = Maps.newHashMap();  
    while (enumeration.hasMoreElements()){  
        String parameter = enumeration.nextElement();  
        parameterMap.put(parameter,request.getParameter(parameter));  
    }  
    String str = JSON.toJSONString(parameterMap);  
    if(obj.length > 0) {  
        logger.info("請求的參數信息為:"+str);
    }  
}

**註意:這裡用到瞭JoinPoint和RequestContextHolder。

1)、通過JoinPoint可以獲得通知的簽名信息,如目標方法名、目標方法參數信息等。

2)、通過RequestContextHolder來獲取請求信息,Session信息。**

5、配置後置返回通知

/** 
 * 後置返回通知 
 * 這裡需要註意的是: 
 *      如果參數中的第一個參數為JoinPoint,則第二個參數為返回值的信息 
 *      如果參數中的第一個參數不為JoinPoint,則第一個參數為returning中對應的參數 
 * returning:限定瞭隻有目標方法返回值與通知方法相應參數類型時才能執行後置返回通知,否則不執行,
 *            對於returning對應的通知方法參數為Object類型將匹配任何目標返回值 
 * @param joinPoint 
 * @param keys 
 */  
@AfterReturning(value = POINT_CUT,returning = "keys")  
public void doAfterReturningAdvice1(JoinPoint joinPoint,Object keys){  
    logger.info("第一個後置返回通知的返回值:"+keys);  
}  
@AfterReturning(value = POINT_CUT,returning = "keys",argNames = "keys")  
public void doAfterReturningAdvice2(String keys){  
    logger.info("第二個後置返回通知的返回值:"+keys);  
}  

6、後置異常通知

/** 
 * 後置異常通知 
 *  定義一個名字,該名字用於匹配通知實現方法的一個參數名,當目標方法拋出異常返回後,將把目標方法拋出的異常傳給通知方法; 
 *  throwing:限定瞭隻有目標方法拋出的異常與通知方法相應參數異常類型時才能執行後置異常通知,否則不執行, 
 *            對於throwing對應的通知方法參數為Throwable類型將匹配任何異常。 
 * @param joinPoint 
 * @param exception 
 */  
@AfterThrowing(value = POINT_CUT,throwing = "exception")  
public void doAfterThrowingAdvice(JoinPoint joinPoint,Throwable exception){  
    //目標方法名:  
    logger.info(joinPoint.getSignature().getName());  
    if(exception instanceof NullPointerException){  
        logger.info("發生瞭空指針異常!!!!!");  
    }  
}  

7、後置最終通知

/** 
 * 後置最終通知(目標方法隻要執行完瞭就會執行後置通知方法) 
 * @param joinPoint 
 */  
@After(value = POINT_CUT)  
public void doAfterAdvice(JoinPoint joinPoint){ 
    logger.info("後置最終通知執行瞭!!!!");  
}  

8、環繞通知

/** 
 * 環繞通知: 
 *   環繞通知非常強大,可以決定目標方法是否執行,什麼時候執行,執行時是否需要替換方法參數,執行完畢是否需要替換返回值。 
 *   環繞通知第一個參數必須是org.aspectj.lang.ProceedingJoinPoint類型 
 */  
@Around(value = POINT_CUT)  
public Object doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint){  
    logger.info("環繞通知的目標方法名:"+proceedingJoinPoint.getSignature().getName());  
    try {  
        Object obj = proceedingJoinPoint.proceed();  
        return obj;  
    } catch (Throwable throwable) {  
        throwable.printStackTrace();  
    }  
    return null;  
}  

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: