SpringAOP+自定義注解實現日志記錄
關於自定義注解基本介紹可參考以往博客:https://www.cnblogs.com/DFX339/p/11386722.html
此文主要是講述如何通過注解標識記錄日志信息,一般我們的Service接口都需要記錄入參信息,參數校驗,方法執行時間等
處理思路:
1.自定義注解,使用的時候通過加入注解即可注入相應的日志信息
2.使用SpringAOP, 識別注解標識的方法,切入日志信息
步驟一: 定義注解類 SystemLog.java
package com.im.nexus.service.utils.logUtils;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @description:系統日志注解(使用在Service類里面的方法上)
* @author: duanfeixia
* @time: 2020/5/12 10:54
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SystemLog {
String methoddesc() default "";//方法描述
}
步驟二:定義切面 SystemLogAspect.java
這里切記需要加入 @Component @Aspect 這兩個注解,@Slf4j 這個注解是日志類的注解 非必選
package com.im.nexus.service.utils.logUtils;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* 自定義日志注解 SystemLog配合AOP注入日志信息
*/
@Component
@Aspect
@Slf4j
public class SystemLogAspect {
// @SystemLog標識為切入點,切面會根據@SystemLog注解來注入數據
@Pointcut("@annotation(com.imodule.nexus.service.utils.logUtils.SystemLog)")
public void logPointCut(){
}
//環繞注入
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long startTime = System.currentTimeMillis();//記錄目標方法的開始執行時間
Object result = point.proceed();//執行目標方法
long methodexecutetime = System.currentTimeMillis() - startTime;
//日志信息記錄
try {
MethodSignature methodSignature = (MethodSignature) point.getSignature();
Method method = methodSignature.getMethod();
SystemLog systemLog = method.getDeclaredAnnotation(SystemLog.class);
String className = point.getTarget().getClass().getName();//類名
String methodName = method.getName();//方法名
//入參信息
Object[] args = point.getArgs();
List<String> list = new ArrayList<String>();
for (Object obj : args) {
list.add(new Gson().toJson(obj));
}
log.info(className+"."+methodName+","+systemLog.methoddesc()+",入參:"+list.toString());
log.info(className+"."+methodName+","+systemLog.methoddesc()+",耗時:"+methodexecutetime+"ms");
} catch (Exception e) {
log.error("日志切入出錯");
}
return result;
}
}
步驟三: 在具體Service實現類的方法上使用 @SystemLog注解
使用示例:@SystemLog(methoddesc = "方法說明內容")
package com.im.nexus.service.impl.prd;
import com.im.common.frame.exception.IMException;
import com.im.nexus.constant.NexusExceptionCodeEnum;
import com.im.nexus.dao.prd.PrdTsarateMapper;
import com.im.nexus.service.utils.BizParamCheckUtils;
import com.im.nexus.service.utils.ExceptionThrowUtils;
import com.im.nexus.service.utils.logUtils.SystemLog;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @description 產品接口實現類
* @date 2020-03-31
* @author duanfeixia
*/
@Service
@Slf4j
public class prdServiceImpl implements prdService {
@Autowired
private PrdTsarateMapper prdTsarateMapper;
@Override
@SystemLog(methoddesc = "是否簡易核保-注解標識")
public PrdResultDTO isSimple(String prdCode) throws IMException {
//入參對象校驗
BizParamCheckUtils.paramPropertyNullCheck("prdServiceImpl.getPrdStaticInfo:prdCode",prdCode);
PrdResultDTO prdResultDTO= new PrdResultDTO();
try {
Integer prdflag = prdTsarateMapper.isSimple(prdCode);
/// 這里遵照了以前的寫法,建議后續使用 1:是,0:否
if (null != prdflag && prdflag > 0) {
// 屬於簡易核保 : 0
prdResultDTO.setIsSimple(SysCnst.STR_FLAG_NO);
} else {
// 不屬於簡易核保 : 1
prdResultDTO.setIsSimple(SysCnst.STR_FLAG_YES);
}
} catch (Exception e) {
log.error("prdServiceImpl.isSimple exception:[prdcode=" + prdCode + "]");
ExceptionThrowUtils.logAndThrowException(NexusExceptionCodeEnum.EXCEPTION_DB_000001, e);
}
return prdResultDTO;
}
}
步驟四:定義測試類,對以上方法進行測試(Junit單元測試)
package com.im.nexus.service.prd;
import com.im.common.frame.exception.IMException;
import com.im.nexus.DTO.prd.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class prdServiceTest {
@Autowired
private prdService prdService;
@Test
public void testisSimple() throws IMException{
try {
PrdResultDTO prdTsarateRtl = prdService.isSimple("12");
log.info("是否簡易核保:"+prdTsarateRtl);
log.info("prdTsarateRtl.getIsSimple:"+prdTsarateRtl.getIsSimple());
} catch (Exception e) {
log.error("ceshi :", e);
}
}
}
執行單元測試后,測試結果如下:
[] 2020-05-12 12:59:33:331 INFO [main] c.i.n.s.u.logUtils.SystemLogAspect 51 - com.im.nexus.service.impl.prd.prdServiceImpl.isSimple,是否簡易核保-PRD,入參:["12"]
[] 2020-05-12 12:59:33:331 INFO [main] c.i.n.s.u.logUtils.SystemLogAspect 52 - com.im.nexus.service.impl.prd.prdServiceImpl.isSimple,是否簡易核保-PRD,耗時:66ms
[] 2020-05-12 12:59:33:331 INFO [main] c.i.n.service.prd.prdServiceTest 26 - 是否簡易核保:PrdTsarateRtl{isSimple=1}
[] 2020-05-12 12:59:33:331 INFO [main] c.i.n.service.prd.prdServiceTest 27 - prdTsarateRtl.getIsSimple:1
前面兩行則是我們通過@SystemLog注解注入的日志內容
后面兩行則是我們在Service實現類的方法中手寫的日志內容
