javascript
Spring系列(十三):AOP相关知识笔记
? ? ? ?? ? ? ? ?
今天給大家分享AOP相關(guān)的知識(shí),希望對(duì)大家能有所幫助!
1、AOP定義
AOP全稱(chēng)為Aspect Oriented Programming,中文含義為:面向切面編程。
通過(guò)預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的技術(shù)。AOP技術(shù)是Spring框架中的一個(gè)重要內(nèi)容。使用AOP技術(shù)可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,可以使業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)也提高了開(kāi)發(fā)的效率。
? ? ? ? ? ? ? ?
2、AOP的用途
使用AOP技術(shù)可以很好的將日志記錄,性能統(tǒng)計(jì),安全控制,事務(wù)處理,異常處理、Web參數(shù)校驗(yàn)等代碼邏輯從業(yè)務(wù)代碼中分離出來(lái),讓開(kāi)發(fā)人員只需要關(guān)注業(yè)務(wù)代碼的編寫(xiě),從而開(kāi)發(fā)效率,節(jié)省開(kāi)發(fā)成本。
3、AOP常用的注解
注解 | 注解說(shuō)明 |
@Aspect | 切面聲明:通常標(biāo)注在類(lèi)、接口(包括注解類(lèi)型)或枚舉上。 |
@Pointcut | 切入點(diǎn)聲明:即切入到哪些目標(biāo)類(lèi)的目標(biāo)方法。 value 屬性指定切入點(diǎn)表達(dá)式,默認(rèn)為 “”,用于被通知注解引用,這樣通知注解只需要關(guān)聯(lián)此切入點(diǎn)聲明即可,無(wú)需再重復(fù)寫(xiě)切入點(diǎn)表達(dá)式 |
@Before | 前置通知:?在目標(biāo)方法(切入點(diǎn))執(zhí)行之前執(zhí)行。value 屬性綁定通知的切入點(diǎn)表達(dá)式,可以關(guān)聯(lián)切入點(diǎn)聲明,也可以直接設(shè)置切入點(diǎn)表達(dá)式 注意:如果在此回調(diào)方法中拋出異常,則目標(biāo)方法不會(huì)再執(zhí)行,會(huì)繼續(xù)執(zhí)行后置通知 -> 異常通知。 |
@After | 后置通知,:在目標(biāo)方法(切入點(diǎn))執(zhí)行之后執(zhí)行 |
@AfterRunning | 返回通知,:在目標(biāo)方法(切入點(diǎn))返回結(jié)果之后執(zhí)行,在 @After 的后面執(zhí)行pointcut 屬性綁定通知的切入點(diǎn)表達(dá)式,優(yōu)先級(jí)高于 value,默認(rèn)為 “” |
@AfterThrowing | 異常通知,:在方法拋出異常之后執(zhí)行, 意味著跳過(guò)返回通知pointcut 屬性綁定通知的切入點(diǎn)表達(dá)式,優(yōu)先級(jí)高于 value,默認(rèn)為 “” 說(shuō)明:如果目標(biāo)方法自己 try-catch 了異常,而沒(méi)有繼續(xù)往外拋,則不會(huì)進(jìn)入此回調(diào)函數(shù) |
@Around | 環(huán)繞通知:目標(biāo)方法執(zhí)行前后分別執(zhí)行一些代碼,發(fā)生異常的時(shí)候執(zhí)行另外一些代碼 |
4、AOP實(shí)現(xiàn)Web統(tǒng)一日志Demo
4.1 新建IErrorCode.java 接口類(lèi)
package com.aop.common.api;/*** 封裝API的錯(cuò)誤碼*/ public interface IErrorCode {long getCode();String getMessage(); }4.2 新建ResultCode.java 接口類(lèi)
package com.aop.common.api;/*** 枚舉了一些常用API操作碼*/ public enum ResultCode implements IErrorCode {SUCCESS(200, "操作成功"),FAILED(500, "操作失敗"),VALIDATE_FAILED(404, "參數(shù)檢驗(yàn)失敗"),UNAUTHORIZED(401, "暫未登錄或token已經(jīng)過(guò)期"),FORBIDDEN(403, "沒(méi)有相關(guān)權(quán)限");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層的日志封裝類(lèi)*/ public class WebLog {/*** 操作描述*/private String description;/*** 操作用戶(hù)*/private String username;/*** 操作時(shí)間*/private Long startTime;/*** 消耗時(shí)間*/private Integer spendTime;/*** 根路徑*/private String basePath;/*** URI*/private String uri;/*** URL*/private String url;/*** 請(qǐng)求類(lèi)型*/private String method;/*** IP地址*/private String ip;/*** 請(qǐng)求參數(shù)*/private Object parameter;/*** 請(qǐng)求返回的結(jié)果*/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 類(lèi)
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;/*** 統(tǒng)一日志處理切面*/ @Aspect @Component @Order(1) public class WebLogAspect {private static final Logger LOGGER = LoggerFactory.getLogger(WebLogAspect.class);//切點(diǎn)定義了通知功能被應(yīng)用的范圍。比如日志切面的應(yīng)用范圍就是所有接口,即所有controller層的接口方@Pointcut("execution(public * com.macro.mall.tiny.controller.*.*(..))")public void webLog() {}// 在目標(biāo)方法調(diào)用前調(diào)用通知功能@Before("webLog()")public void doBefore(JoinPoint joinPoint) throws Throwable {}// 在目標(biāo)方法成功執(zhí)行之后調(diào)用通知功能@AfterReturning(value = "webLog()", returning = "ret")public void doAfterReturning(Object ret) throws Throwable {}// 通知包裹了目標(biāo)方法,在目標(biāo)方法調(diào)用之前和之后執(zhí)行自定義的行為@Around("webLog()")public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {long startTime = System.currentTimeMillis();//獲取當(dāng)前請(qǐng)求對(duì)象ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();//記錄請(qǐng)求信息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;}/*** 根據(jù)方法和傳入的參數(shù)獲取請(qǐng)求參數(shù)*/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注解修飾的參數(shù)作為請(qǐng)求參數(shù)RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);if (requestBody != null) {argList.add(args[i]);}//將RequestParam注解修飾的參數(shù)作為請(qǐng)求參數(shù)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 新建測(cè)試控制器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;} }請(qǐng)求參數(shù):localhost:8080/TestLog/Test?name=121
輸出結(jié)果:
{"result":"hello121","basePath":"http://localhost:8080","method":"GET","startTime":1645883742030,"uri":"/TestLog/Test","url":"http://localhost:8080/TestLog/Test","spendTime":4695}
IT技術(shù)分享社區(qū)
個(gè)人博客網(wǎng)站:https://programmerblog.xyz
文章推薦程序員效率:畫(huà)流程圖常用的工具程序員效率:整理常用的在線筆記軟件遠(yuǎn)程辦公:常用的遠(yuǎn)程協(xié)助軟件,你都知道嗎?51單片機(jī)程序下載、ISP及串口基礎(chǔ)知識(shí)硬件:斷路器、接觸器、繼電器基礎(chǔ)知識(shí)
總結(jié)
以上是生活随笔為你收集整理的Spring系列(十三):AOP相关知识笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: laydate时间控件有时候无效_新角度
- 下一篇: javascript的stack ove