背景
在工作中,日志是查找BUG的重要手段之一,正常的方式就是代碼中通過面向過程的方式,即在代碼中将想要顯示的變量輸出。
然而,在是調試當中,經常需要檢視方法的傳入參數,但是如果代碼中沒有log,那查日志就GG了;但是在每個方法都log一段代碼,那就有點累贅了,是以接下來将用Spring中的AOP(切面程式設計)的方式,實作方法環繞日志。
需求
用切面程式設計的方式,記錄代碼運作中傳入變量的值。
步驟
1.maven依賴
2.編寫切面
3.注入bean和配置Pointcut
過程
- maven依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${springframework.version}</version>
</dependency>
- 編寫切面(用于記錄方法參數的日志操作)
package com.liushiyao.common;
import java.util.Arrays;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
public class LogAspect {
private final Logger logger = Logger.getLogger(this.getClass());
/**
* 輸出調用的參數
*
* @param joinPoint
*/
public void after(JoinPoint joinPoint) {
//擷取參數清單
Object[] arguments = joinPoint.getArgs();
//方法名
String methodName = joinPoint.getSignature().getName();
String targetName = joinPoint.getTarget().getClass().getName();
logger.debug("{refer}" + targetName + "." + methodName + ",{arg}" + Arrays.toString(arguments));
}
}
- 類LogAspect即為AOP程式設計中的Aspect,裡面用來聲明before(略),after,around(略)
- after方法即為AOP程式設計中的Advice,是AOP程式的具體操作。
- after方法是調用方法之後執行的,通過JoinPoint對象,可以獲得方法的參數清單已經對應的名字等等
-
注入bean和配置Pointcut
在dispatcher-servlet.xml增加以下代碼
<!--指定掃描目錄-->
<aop:aspectj-autoproxy proxy-target-class="true" />
<!--将日志類注入到bean中。-->
<bean id="logAspect" class="com.liushiyao.common.LogAspect"></bean>
<aop:config>
<!--調用日志類-->
<aop:aspect id="LogAspect" ref="logAspect">
<!--配置在service包下所有的類在調用之前都會被攔截-->
<aop:pointcut id="log" expression="execution(* com.liushiyao.blog.service..*.*(..))"/>
<!--方法前觸發 <aop:before pointcut-ref="log" method="before"/>-->
<!-- 方法後觸發 --><aop:after pointcut-ref="log" method="after"/>
<!-- 環繞觸發 <aop:around pointcut-ref="log" method="around"/> -->
</aop:aspect>
</aop:config>
- pointcut(切點),比對service下的所有方法,當service中的方法被調用的時候,就會執行after方法。
運作
寫個測試的controller
@RequestMapping("/aop")
@CrossOrigin
private void aop(Integer integer,String string){
testService.aopLogTest(integer,string);
}
- controller使用到了testService中的aopLogTest的方法
而aopLogTest方法隻是個空方法,
public void aopLogTest(int arg,String strArg){
}
調用接口,輸入日志
[DEBUG] 2019-10-11 00:08:58,739 method:com.liushiyao.common.LogAspect.after(LogAspect.java:30)
{refer}com.liushiyao.blog.service.TestService.aopLogTest,{arg}[1, 我是字元串]
從日志可以看出,通過AOP的方式被調用的方法的參數清單自動的以日志的方式記錄了下來(即使被調用的方法中沒有手動把方法參數列印出來),這就是面向切面程式設計。
拓展
pointcut是通過配置檔案比對的,那能不能通過注解的方式(當然,比對的方式也可以實作,隻是注解更加的靈活),想要記錄哪些方法就記錄哪些方法?
當然可以!
- 先定義一個注解
import com.liushiyao.common.def.Log;
import java.lang.annotation.*;
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AutoLog {
//日志類型
public int type () default Log.Type.DEBUG;
}
- 定義日志類型
public class Log {
public static final class Type{
public static final int DEBUG = 1;
public static final int INFO = 2;
public static final int ERROR = 3;
}
}
- 對after方法進行改造
/**
* 輸出調用的參數
*
* @param joinPoint
*/
public void after(JoinPoint joinPoint) {
//擷取參數清單
Object[] arguments = joinPoint.getArgs();
//方法名
String methodName = joinPoint.getSignature().getName();
String targetName = joinPoint.getTarget().getClass().getName();
Class targetClass = null;
try {
targetClass =
Class.forName(targetName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Method methods [] = targetClass.getMethods();
for (Method method:methods){
//找到對應的方法
if(method.getName().equals(methodName)){
//是否有注解
AutoLog autoLog = method.getAnnotation(AutoLog.class);
if(autoLog != null){
if(autoLog.type() == Log.Type.DEBUG){
logger.debug("{refer}" + targetName +"." + methodName + ",{arg}" + Arrays.toString(arguments));
}else if(autoLog.type() == Log.Type.INFO){
logger.info("{refer}" + targetName +"." + methodName + ",{arg}" + Arrays.toString(arguments));
}else if(autoLog.type() == Log.Type.ERROR){
logger.error("{refer}" + targetName +"." + methodName + ",{arg}" + Arrays.toString(arguments));
}
}
}
}
}
- 對需要打日志的方式加注解
- TestService
public void aopLogTest(int arg,String strArg) {
}
@AutoLog(type = Log.Type.INFO)
public void aopLogTest2(String strArg){
}
@RequestMapping("/aop")
private void aop(Integer integer,String string){
testService.aopLogTest(integer,string);
testService.aopLogTest2(string);
}
- 運作結果
[INFO ] 2019-10-12 22:16:17,020 method:com.liushiyao.common.LogAspect.after(LogAspect.java:52)
{refer}com.liushiyao.blog.service.testService.aopLogTest2,{arg}[555]
可以看出隻有加了@AutoLog的方法才會記錄日志。
以上就是對環繞日志應用和注解日志的介紹,如有錯誤,歡迎指正