javascript
Spring系列(十三):AOP相关知识笔记
? ? ? ?? ? ? ? ?
今天給大家分享AOP相關的知識,希望對大家能有所幫助!
1、AOP定義
AOP全稱為Aspect Oriented Programming,中文含義為:面向切面編程。
通過預編譯方式和運行期動態代理實現程序功能的統一維護的技術。AOP技術是Spring框架中的一個重要內容。使用AOP技術可以對業務邏輯的各個部分進行隔離,可以使業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時也提高了開發的效率。
? ? ? ? ? ? ? ?
2、AOP的用途
使用AOP技術可以很好的將日志記錄,性能統計,安全控制,事務處理,異常處理、Web參數校驗等代碼邏輯從業務代碼中分離出來,讓開發人員只需要關注業務代碼的編寫,從而開發效率,節省開發成本。
3、AOP常用的注解
注解 | 注解說明 |
@Aspect | 切面聲明:通常標注在類、接口(包括注解類型)或枚舉上。 |
@Pointcut | 切入點聲明:即切入到哪些目標類的目標方法。 value 屬性指定切入點表達式,默認為 “”,用于被通知注解引用,這樣通知注解只需要關聯此切入點聲明即可,無需再重復寫切入點表達式 |
@Before | 前置通知:?在目標方法(切入點)執行之前執行。value 屬性綁定通知的切入點表達式,可以關聯切入點聲明,也可以直接設置切入點表達式 注意:如果在此回調方法中拋出異常,則目標方法不會再執行,會繼續執行后置通知 -> 異常通知。 |
@After | 后置通知,:在目標方法(切入點)執行之后執行 |
@AfterRunning | 返回通知,:在目標方法(切入點)返回結果之后執行,在 @After 的后面執行pointcut 屬性綁定通知的切入點表達式,優先級高于 value,默認為 “” |
@AfterThrowing | 異常通知,:在方法拋出異常之后執行, 意味著跳過返回通知pointcut 屬性綁定通知的切入點表達式,優先級高于 value,默認為 “” 說明:如果目標方法自己 try-catch 了異常,而沒有繼續往外拋,則不會進入此回調函數 |
@Around | 環繞通知:目標方法執行前后分別執行一些代碼,發生異常的時候執行另外一些代碼 |
4、AOP實現Web統一日志Demo
4.1 新建IErrorCode.java 接口類
package com.aop.common.api;/*** 封裝API的錯誤碼*/ public interface IErrorCode {long getCode();String getMessage(); }4.2 新建ResultCode.java 接口類
package com.aop.common.api;/*** 枚舉了一些常用API操作碼*/ public enum ResultCode implements IErrorCode {SUCCESS(200, "操作成功"),FAILED(500, "操作失敗"),VALIDATE_FAILED(404, "參數檢驗失敗"),UNAUTHORIZED(401, "暫未登錄或token已經過期"),FORBIDDEN(403, "沒有相關權限");private long code;private String message;private ResultCode(long code, String message) {this.code = code;this.message = message;}public long getCode() {return code;}public String getMessage() {return message;} }4.3 新建WebLog.java
package com.aop.common.dto;/*** Controller層的日志封裝類*/ public class WebLog {/*** 操作描述*/private String description;/*** 操作用戶*/private String username;/*** 操作時間*/private Long startTime;/*** 消耗時間*/private Integer spendTime;/*** 根路徑*/private String basePath;/*** URI*/private String uri;/*** URL*/private String url;/*** 請求類型*/private String method;/*** IP地址*/private String ip;/*** 請求參數*/private Object parameter;/*** 請求返回的結果*/private Object result;public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public Long getStartTime() {return startTime;}public void setStartTime(Long startTime) {this.startTime = startTime;}public Integer getSpendTime() {return spendTime;}public void setSpendTime(Integer spendTime) {this.spendTime = spendTime;}public String getBasePath() {return basePath;}public void setBasePath(String basePath) {this.basePath = basePath;}public String getUri() {return uri;}public void setUri(String uri) {this.uri = uri;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String getMethod() {return method;}public void setMethod(String method) {this.method = method;}public String getIp() {return ip;}public void setIp(String ip) {this.ip = ip;}public Object getParameter() {return parameter;}public void setParameter(Object parameter) {this.parameter = parameter;}public Object getResult() {return result;}public void setResult(Object result) {this.result = result;} }4.4 新建WebLogAspect.java 類
package com.aop.common.component;import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; import cn.hutool.json.JSONUtil; import com.aop.common.dto.WebLog; import io.swagger.annotations.ApiOperation; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;/*** 統一日志處理切面*/ @Aspect @Component @Order(1) public class WebLogAspect {private static final Logger LOGGER = LoggerFactory.getLogger(WebLogAspect.class);//切點定義了通知功能被應用的范圍。比如日志切面的應用范圍就是所有接口,即所有controller層的接口方@Pointcut("execution(public * com.macro.mall.tiny.controller.*.*(..))")public void webLog() {}// 在目標方法調用前調用通知功能@Before("webLog()")public void doBefore(JoinPoint joinPoint) throws Throwable {}// 在目標方法成功執行之后調用通知功能@AfterReturning(value = "webLog()", returning = "ret")public void doAfterReturning(Object ret) throws Throwable {}// 通知包裹了目標方法,在目標方法調用之前和之后執行自定義的行為@Around("webLog()")public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {long startTime = System.currentTimeMillis();//獲取當前請求對象ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();//記錄請求信息WebLog webLog = new WebLog();Object result = joinPoint.proceed();Signature signature = joinPoint.getSignature();MethodSignature methodSignature = (MethodSignature) signature;Method method = methodSignature.getMethod();if (method.isAnnotationPresent(ApiOperation.class)) {ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);webLog.setDescription(apiOperation.value());}long endTime = System.currentTimeMillis();String urlStr = request.getRequestURL().toString();webLog.setBasePath(StrUtil.removeSuffix(urlStr, URLUtil.url(urlStr).getPath()));webLog.setIp(request.getRemoteUser());webLog.setMethod(request.getMethod());webLog.setParameter(getParameter(method, joinPoint.getArgs()));webLog.setResult(result);webLog.setSpendTime((int) (endTime - startTime));webLog.setStartTime(startTime);webLog.setUri(request.getRequestURI());webLog.setUrl(request.getRequestURL().toString());LOGGER.info("{}", JSONUtil.parse(webLog));return result;}/*** 根據方法和傳入的參數獲取請求參數*/private Object getParameter(Method method, Object[] args) {List<Object> argList = new ArrayList<>();Parameter[] parameters = method.getParameters();for (int i = 0; i < parameters.length; i++) {//將RequestBody注解修飾的參數作為請求參數RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);if (requestBody != null) {argList.add(args[i]);}//將RequestParam注解修飾的參數作為請求參數RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);if (requestParam != null) {Map<String, Object> map = new HashMap<>();String key = parameters[i].getName();if (!StringUtils.isEmpty(requestParam.value())) {key = requestParam.value();}map.put(key, args[i]);argList.add(map);}}if (argList.size() == 0) {return null;} else if (argList.size() == 1) {return argList.get(0);} else {return argList;}} }4.5 新建測試控制器TestLogController.java
package com.aop.common.controller;import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;@Controller @RequestMapping("/TestLog") public class TestLogController {@RequestMapping("/Test")public String Test(String name){return "hello"+name;} }請求參數:localhost:8080/TestLog/Test?name=121
輸出結果:
{"result":"hello121","basePath":"http://localhost:8080","method":"GET","startTime":1645883742030,"uri":"/TestLog/Test","url":"http://localhost:8080/TestLog/Test","spendTime":4695}
IT技術分享社區
個人博客網站:https://programmerblog.xyz
文章推薦程序員效率:畫流程圖常用的工具程序員效率:整理常用的在線筆記軟件遠程辦公:常用的遠程協助軟件,你都知道嗎?51單片機程序下載、ISP及串口基礎知識硬件:斷路器、接觸器、繼電器基礎知識
總結
以上是生活随笔為你收集整理的Spring系列(十三):AOP相关知识笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: laydate时间控件有时候无效_新角度
- 下一篇: javascript的stack ove