Springboot使用Aspect實(shí)現(xiàn)切面日志
點(diǎn)擊上方“程序員大白”,選擇“星標(biāo)”公眾號(hào)
重磅干貨,第一時(shí)間送達(dá)
前言
今天我們來說說spring中的切面Aspect,這是Spring的一大優(yōu)勢(shì)。面向切面編程往往讓我們的開發(fā)更加低耦合,也大大減少了代碼量,同時(shí)呢讓我們更專注于業(yè)務(wù)模塊的開發(fā),把那些與業(yè)務(wù)無關(guān)的東西提取出去,便于后期的維護(hù)和迭代。
好了,廢話少說!我們直接步入正題
以系統(tǒng)日志為例
首先,我們先做一些準(zhǔn)備工作。
1、新建一個(gè)Springboot工程
2、添加必要的依賴
AOP 必須
<dependency>
?<groupId>org.springframework.bootgroupId>
?<artifactId>spring-boot-starter-aopartifactId>
dependency>
gson主要是我用于數(shù)據(jù)的處理,不是必須的
<dependency>
?<groupId>com.google.code.gsongroupId>
?<artifactId>gsonartifactId>
?<version>2.8.1version>
dependency>
個(gè)人喜好
<dependency>
?<groupId>org.springframework.bootgroupId>
?<artifactId>spring-boot-devtoolsartifactId>
?<scope>runtimescope>
dependency>
<dependency>
?<groupId>org.projectlombokgroupId>
?<artifactId>lombokartifactId>
?<optional>trueoptional>
dependency>
3、日志實(shí)體類和service
package?com.space.aspect.bo;
?
import?lombok.Data;
?
/**
?*?系統(tǒng)日志bo
?*?@author?zhuzhe
?*/
@Data
public?class?SysLogBO?{
?
????private?String?className;
?
????private?String?methodName;
?
????private?String?params;
?
????private?Long?exeuTime;
?
????private?String?remark;
?
????private?String?createDate;
}
package?com.space.aspect.service;
?
import?com.space.aspect.bo.SysLogBO;
import?lombok.extern.slf4j.Slf4j;
import?org.springframework.stereotype.Service;
?
/**
?*?@author?zhuzhe
?*/
@Slf4j
@Service
public?class?SysLogService?{
?
????public?boolean?save(SysLogBO?sysLogBO){
????????//?這里就不做具體實(shí)現(xiàn)了
????????log.info(sysLogBO.getParams());
????????return?true;
????}
}
4、定義日志注解
這里呢,我們記錄日志使用注解的形式。所以,先定義一個(gè)注解
package?com.space.aspect.anno;
?
import?java.lang.annotation.*;
?
/**
?*?定義系統(tǒng)日志注解
?*?@author?zhuzhe
?*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public?@interface?SysLog?{
????String?value()?default?"";
}
5、聲明切面,完成日志記錄
以上4點(diǎn)我們的準(zhǔn)備工作已經(jīng)完成。接下來就是重點(diǎn)了
這里需要你對(duì)AOP有一定的了解。起碼知道切點(diǎn)表達(dá)式、環(huán)繞通知、前置通知、后置通知等。。。
package?com.space.aspect.aspect;
?
import?com.google.gson.Gson;
import?com.space.aspect.anno.SysLog;
import?com.space.aspect.bo.SysLogBO;
import?com.space.aspect.service.SysLogService;
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.beans.factory.annotation.Autowired;
import?org.springframework.stereotype.Component;
?
import?java.lang.reflect.Method;
import?java.text.SimpleDateFormat;
import?java.util.ArrayList;
import?java.util.Date;
import?java.util.List;
?
/**
?*?系統(tǒng)日志切面
?*?@author?zhuzhe
?*/
@Aspect??//?使用@Aspect注解聲明一個(gè)切面
@Component
public?class?SysLogAspect?{
?
????@Autowired
????private?SysLogService?sysLogService;
?
????/**
?????*?這里我們使用注解的形式
?????*?當(dāng)然,我們也可以通過切點(diǎn)表達(dá)式直接指定需要攔截的package,需要攔截的class?以及?method
?????*?切點(diǎn)表達(dá)式:???execution(...)
?????*/
????@Pointcut("@annotation(com.space.aspect.anno.SysLog)")
????public?void?logPointCut()?{}
?
????/**
?????*?環(huán)繞通知?@Around??,?當(dāng)然也可以使用?@Before?(前置通知)??@After?(后置通知)
?????*?@param?point
?????*?@return
?????*?@throws?Throwable
?????*/
????@Around("logPointCut()")
????public?Object?around(ProceedingJoinPoint?point)?throws?Throwable?{
????????long?beginTime?=?System.currentTimeMillis();
????????Object?result?=?point.proceed();
????????long?time?=?System.currentTimeMillis()?-?beginTime;
????????try?{
????????????saveLog(point,?time);
????????}?catch?(Exception?e)?{
????????}
????????return?result;
????}
?
????/**
?????*?保存日志
?????*?@param?joinPoint
?????*?@param?time
?????*/
????private?void?saveLog(ProceedingJoinPoint?joinPoint,?long?time)?{
????????MethodSignature?signature?=?(MethodSignature)?joinPoint.getSignature();
????????Method?method?=?signature.getMethod();
????????SysLogBO?sysLogBO?=?new?SysLogBO();
????????sysLogBO.setExeuTime(time);
????????SimpleDateFormat?dateFormat?=?new?SimpleDateFormat("yyyy-MM-dd?hh:mm:ss");
????????sysLogBO.setCreateDate(dateFormat.format(new?Date()));
????????SysLog?sysLog?=?method.getAnnotation(SysLog.class);
????????if(sysLog?!=?null){
????????????//注解上的描述
????????????sysLogBO.setRemark(sysLog.value());
????????}
????????//請(qǐng)求的?類名、方法名
????????String?className?=?joinPoint.getTarget().getClass().getName();
????????String?methodName?=?signature.getName();
????????sysLogBO.setClassName(className);
????????sysLogBO.setMethodName(methodName);
????????//請(qǐng)求的參數(shù)
????????Object[]?args?=?joinPoint.getArgs();
????????try{
????????????List?list?=?new?ArrayList();
????????????for?(Object?o?:?args)?{
????????????????list.add(new?Gson().toJson(o));
????????????}
????????????sysLogBO.setParams(list.toString());
????????}catch?(Exception?e){?}
????????sysLogService.save(sysLogBO);
????}
}
6、測(cè)試
接下來,我們就來測(cè)試一下吧
package?com.space.aspect.controller;
?
import?com.space.aspect.anno.SysLog;
import?org.springframework.web.bind.annotation.GetMapping;
import?org.springframework.web.bind.annotation.RequestParam;
import?org.springframework.web.bind.annotation.RestController;
?
/**
?*?@author?zhuzhe
?*/
@RestController
public?class?TestController?{
?
????@SysLog("測(cè)試")
????@GetMapping("/test")
????public?String?test(@RequestParam("name")?String?name){
????????return?name;
????}
}
啟動(dòng)項(xiàng)目,訪問我們的test方法。
我們?cè)趕ervice里打一個(gè)斷點(diǎn)


可以看到,我們所需要的值都成功拿到了。
這樣,我們就成功實(shí)現(xiàn)了使用Aspect實(shí)現(xiàn)切面記錄日志。
源碼:https://github.com/zhuzhegithub/springboot-aop-aspect
來源:blog.csdn.net/zhuzhezhuzhe1/
article/details/80565067
推薦閱讀
關(guān)于程序員大白
程序員大白是一群哈工大,東北大學(xué),西湖大學(xué)和上海交通大學(xué)的碩士博士運(yùn)營(yíng)維護(hù)的號(hào),大家樂于分享高質(zhì)量文章,喜歡總結(jié)知識(shí),歡迎關(guān)注[程序員大白],大家一起學(xué)習(xí)進(jìn)步!


