一:功能簡介
本文主要記錄如何使用aop切面的方式來實現日志記錄功能。
主要記錄的信息有: 操作人,方法名,參數,運行時間,操作類型(增刪改查),詳細描述,返回值。
二:項目結構圖

如果想學習Java工程化、高性能及分布式、深入淺出。微服務、Spring,MyBatis,Netty源碼分析的朋友可以加我的Java高級交流:854630135,群里有阿里大牛直播講解技術,以及Java大型互聯網技術的視頻免費分享給大家。
三:代碼實現
1.配置文件
這里只有兩個配置:1)server.port=11000,設置項目啟動的端口號,防止被其他服務占用;2)spring.aop.auto=true,開啟spring的aop配置,簡單明了,不需要多配置其他的配置或注解。application.yml文件server: port: 11000spring: aop: auto: true #啟動aop配置
2.AOP切點類
這個是最主要的類,可以使用自定義注解或針對包名實現AOP增強。
1)這里實現了對自定義注解的環繞增強切點,對使用了自定義注解的方法進行AOP切面處理;
2)對方法運行時間進行監控;
3)對方法名,參數名,參數值,對日志描述的優化處理;
在方法上增加@Aspect 注解聲明切面,使用@Pointcut 注解定義切點,標記方法。
使用切點增強的時機注解:@Before,@Around,@AfterReturning,@AfterThrowing,@After
package com.wwj.springboot.aop;import com.alibaba.fastjson.JSON;import com.wwj.springboot.annotation.OperationLogDetail;import com.wwj.springboot.model.OperationLog;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.stereotype.Component;import java.util.Date;import java.util.HashMap;import java.util.Map;import java.util.UUID;/** * Created by IntelliJ IDEA * * @author weiwenjun * @date 2018/9/12 */@Aspect@Componentpublic class LogAspect { /** * 此處的切點是注解的方式,也可以用包名的方式達到相同的效果 * '@Pointcut("execution(* com.wwj.springboot.service.impl.*.*(..))")' */ @Pointcut("@annotation(com.wwj.springboot.annotation.OperationLogDetail)") public void operationLog(){} /** * 環繞增強,相當于MethodInterceptor */ @Around("operationLog()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { Object res = null; long time = System.currentTimeMillis(); try { res = joinPoint.proceed(); time = System.currentTimeMillis() - time; return res; } finally { try { //方法執行完成后增加日志 addOperationLog(joinPoint,res,time); }catch (Exception e){ System.out.println("LogAspect 操作失敗:" + e.getMessage()); e.printStackTrace(); } } } private void addOperationLog(JoinPoint joinPoint, Object res, long time){ MethodSignature signature = (MethodSignature)joinPoint.getSignature(); OperationLog operationLog = new OperationLog(); operationLog.setRunTime(time); operationLog.setReturnValue(JSON.toJSONString(res)); operationLog.setId(UUID.randomUUID().toString()); operationLog.setArgs(JSON.toJSONString(joinPoint.getArgs())); operationLog.setCreateTime(new Date()); operationLog.setMethod(signature.getDeclaringTypeName() + "." + signature.getName()); operationLog.setUserId("#{currentUserId}"); operationLog.setUserName("#{currentUserName}"); OperationLogDetail annotation = signature.getMethod().getAnnotation(OperationLogDetail.class); if(annotation != null){ operationLog.setLevel(annotation.level()); operationLog.setDescribe(getDetail(((MethodSignature)joinPoint.getSignature()).getParameterNames(),joinPoint.getArgs(),annotation)); operationLog.setOperationType(annotation.operationType().getValue()); operationLog.setOperationUnit(annotation.operationUnit().getValue()); } //TODO 這里保存日志 System.out.println("記錄日志:" + operationLog.toString());// operationLogService.insert(operationLog); } /** * 對當前登錄用戶和占位符處理 * @param argNames 方法參數名稱數組 * @param args 方法參數數組 * @param annotation 注解信息 * @return 返回處理后的描述 */ private String getDetail(String[] argNames, Object[] args, OperationLogDetail annotation){ Map map = new HashMap<>(4); for(int i = 0;i < argNames.length;i++){ map.put(argNames[i],args[i]); } String detail = annotation.detail(); try { detail = "'" + "#{currentUserName}" + "'=》" + annotation.detail(); for (Map.Entry entry : map.entrySet()) { Object k = entry.getKey(); Object v = entry.getValue(); detail = detail.replace("{{" + k + "}}