成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術文章
文章詳情頁

SpringBoot Aop 詳解和多種使用場景解析

瀏覽:85日期:2023-02-20 10:25:03
前言

aop面向切面編程,是編程中一個很重要的思想本篇文章主要介紹的是SpringBoot切面Aop的使用和案例

什么是aop

AOP(Aspect OrientedProgramming):面向切面編程,面向切面編程(也叫面向方面編程),是目前軟件開發中的一個熱點,也是Spring框架中的一個重要內容。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。

使用場景

利用AOP可以對我們邊緣業務進行隔離,降低無關業務邏輯耦合性。提高程序的可重用性,同時提高了開發的效率。一般用于日志記錄,性能統計,安全控制,權限管理,事務處理,異常處理,資源池管理。使用場景

為什么需要面向切面編程

面向對象編程(OOP)的好處是顯而易見的,缺點也同樣明顯。當需要為多個不具有繼承關系的對象添加一個公共的方法的時候,例如日志記錄、性能監控等,如果采用面向對象編程的方法,需要在每個對象里面都添加相同的方法,這樣就產生了較大的重復工作量和大量的重復代碼,不利于維護。面向切面編程(AOP)是面向對象編程的補充,簡單來說就是統一處理某一“切面”的問題的編程思想。如果使用AOP的方式進行日志的記錄和處理,所有的日志代碼都集中于一處,不需要再每個方法里面都去添加,極大減少了重復代碼。

技術要點 通知(Advice)包含了需要用于多個應用對象的橫切行為,完全聽不懂,沒關系,通俗一點說就是定義了“什么時候”和“做什么”。 連接點(Join Point)是程序執行過程中能夠應用通知的所有點。 切點(Poincut)是定義了在“什么地方”進行切入,哪些連接點會得到通知。顯然,切點一定是連接點。 切面(Aspect)是通知和切點的結合。通知和切點共同定義了切面的全部內容——是什么,何時,何地完成功能。 引入(Introduction)允許我們向現有的類中添加新方法或者屬性。 織入(Weaving)是把切面應用到目標對象并創建新的代理對象的過程,分為編譯期織入、類加載期織入和運行期織入。整合使用導入依賴

在springboot中使用aop要導aop依賴

<!--aop 切面--><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId></dependency>

注意這里版本依賴于spring-boot-start-parent父pom中的spring-boot-dependencies

編寫攔截的bean

這里我們定義一個controller用于攔截所有請求的記錄

@RestControllerpublic class AopController { @RequestMapping('/hello') public String sayHello(){System.out.println('hello');return 'hello'; }}定義切面

SpringBoot在使用切面的時候采用@Aspect注解對POJO進行標注,該注解表明該類不僅僅是一個POJO,還是一個切面容器

定義切點

切點是通過@Pointcut注解和切點表達式定義的。

@Pointcut注解可以在一個切面內定義可重用的切點。

由于Spring切面粒度最小是達到方法級別,而execution表達式可以用于明確指定方法返回類型,類名,方法名和參數名等與方法相關的部件,并且實際中,大部分需要使用AOP的業務場景也只需要達到方法級別即可,因而execution表達式的使用是最為廣泛的。如圖是execution表達式的語法:

SpringBoot Aop 詳解和多種使用場景解析

execution表示在方法執行的時候觸發。以“”開頭,表明方法返回值類型為任意類型。然后是全限定的類名和方法名,“”可以表示任意類和任意方法。對于方法參數列表,可以使用“..”表示參數為任意類型。如果需要多個表達式,可以使用“&&”、“||”和“!”完成與、或、非的操作。

定義通知

通知有五種類型,分別是:

前置通知(@Before):在目標方法調用之前調用通知 后置通知(@After):在目標方法完成之后調用通知 環繞通知(@Around):在被通知的方法調用之前和調用之后執行自定義的方法 返回通知(@AfterReturning):在目標方法成功執行之后調用通知 異常通知(@AfterThrowing):在目標方法拋出異常之后調用通知

代碼中定義了三種類型的通知,使用@Before注解標識前置通知,打印“beforeAdvice...”,使用@After注解標識后置通知,打印“AfterAdvice...”,使用@Around注解標識環繞通知,在方法執行前和執行之后分別打印“before”和“after”。這樣一個切面就定義好了,代碼如下:

@Aspect@Componentpublic class AopAdvice { @Pointcut('execution (* com.shangguan.aop.controller.*.*(..))') public void test() { } @Before('test()') public void beforeAdvice() {System.out.println('beforeAdvice...'); } @After('test()') public void afterAdvice() {System.out.println('afterAdvice...'); } @Around('test()') public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {System.out.println('before');try { proceedingJoinPoint.proceed();} catch (Throwable t) { t.printStackTrace();}System.out.println('after'); }}

運行結果

SpringBoot Aop 詳解和多種使用場景解析

案例場景

這里我們通過一個日志記錄場景來完整的使用Aop切面業務層只需關心代碼邏輯實現而不用關心請求參數和響應參數的日志記錄

那么首先我們需要自定義一個全局日志記錄的切面類GlobalLogAspect

然后在該類添加@Aspect注解,然后在定義一個公共的切入點(Pointcut),指向需要處理的包,然后在定義一個前置通知(添加@Before注解),后置通知(添加@AfterReturning)和環繞通知(添加@Around)方法實現即可

日志信息類

package cn.soboys.core;import lombok.Data;/** * @author kenx * @version 1.0 * @date 2021/6/18 18:48 * 日志信息 */@Datapublic class LogSubject { /** * 操作描述 */ private String description; /** * 操作用戶 */ private String username; /** * 操作時間 */ private String startTime; /** * 消耗時間 */ private String spendTime; /** * URL */ private String url; /** * 請求類型 */ private String method; /** * IP地址 */ private String ip; /** * 請求參數 */ private Object parameter; /** * 請求返回的結果 */ private Object result; /** * 城市 */ private String city; /** * 請求設備信息 */ private String device;}全局日志攔截

package cn.soboys.core;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.reflect.MethodSignature;import java.lang.reflect.Method;/** * @author kenx * @version 1.0 * @date 2021/6/18 14:52 * 切面 */public class BaseAspectSupport { public Method resolveMethod(ProceedingJoinPoint point) {MethodSignature signature = (MethodSignature)point.getSignature();Class<?> targetClass = point.getTarget().getClass();Method method = getDeclaredMethod(targetClass, signature.getName(),signature.getMethod().getParameterTypes());if (method == null) { throw new IllegalStateException('無法解析目標方法: ' + signature.getMethod().getName());}return method; } private Method getDeclaredMethod(Class<?> clazz, String name, Class<?>... parameterTypes) {try { return clazz.getDeclaredMethod(name, parameterTypes);} catch (NoSuchMethodException e) { Class<?> superClass = clazz.getSuperclass(); if (superClass != null) {return getDeclaredMethod(superClass, name, parameterTypes); }}return null; }}

GlobalLogAspect類

package cn.soboys.core;import cn.hutool.core.date.DateUtil;import cn.hutool.core.date.TimeInterval;import cn.hutool.json.JSONUtil;import cn.soboys.core.utils.HttpContextUtil;import io.swagger.annotations.ApiOperation;import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestParam;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;/** * @author kenx * @version 1.0 * @date 2021/6/18 15:22 * 全局日志記錄器 */@Slf4j@Aspect@Componentpublic class GlobalLogAspect extends BaseAspectSupport { /** * 定義切面Pointcut */ @Pointcut('execution(public * cn.soboys.mallapi.controller.*.*(..))') public void log() { } /** * 環繞通知 * * @param joinPoint * @return */ @Around('log()') public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {LogSubject logSubject = new LogSubject();//記錄時間定時器TimeInterval timer = DateUtil.timer(true);//執行結果Object result = joinPoint.proceed();logSubject.setResult(result);//執行消耗時間String endTime = timer.intervalPretty();logSubject.setSpendTime(endTime);//執行參數Method method = resolveMethod(joinPoint);logSubject.setParameter(getParameter(method, joinPoint.getArgs()));HttpServletRequest request = HttpContextUtil.getRequest();// 接口請求時間logSubject.setStartTime(DateUtil.now());//請求鏈接logSubject.setUrl(request.getRequestURL().toString());//請求方法GET,POST等logSubject.setMethod(request.getMethod());//請求設備信息logSubject.setDevice(HttpContextUtil.getDevice());//請求地址logSubject.setIp(HttpContextUtil.getIpAddr());//接口描述if (method.isAnnotationPresent(ApiOperation.class)) { ApiOperation apiOperation = method.getAnnotation(ApiOperation.class); logSubject.setDescription(apiOperation.value());}String a = JSONUtil.toJsonPrettyStr(logSubject);log.info(a);return result; } /** * 根據方法和傳入的參數獲取請求參數 */ private Object getParameter(Method method, Object[] args) {List<Object> argList = new ArrayList<>();Parameter[] parameters = method.getParameters();Map<String, Object> map = new HashMap<>();for (int i = 0; i < parameters.length; i++) { //將RequestBody注解修飾的參數作為請求參數 RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class); //將RequestParam注解修飾的參數作為請求參數 RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class); String key = parameters[i].getName(); if (requestBody != null) {argList.add(args[i]); } else if (requestParam != null) {map.put(key, args[i]); } else {map.put(key, args[i]); }}if (map.size() > 0) { argList.add(map);}if (argList.size() == 0) { return null;} else if (argList.size() == 1) { return argList.get(0);} else { return argList;} }}

到此這篇關于SpringBoot Aop 詳解和多種使用場景的文章就介紹到這了,更多相關SpringBoot Aop使用內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Spring
相關文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
337p粉嫩大胆噜噜噜噜噜91av| 日韩免费成人网| 欧美在线制服丝袜| 亚洲精品成a人| 色综合天天视频在线观看 | 青椒成人免费视频| 国产亚洲精品久久久久婷婷瑜伽| 久久久久综合网| 国产成人av影院| 精品视频一区二区三区免费| 天堂av在线一区| 中文高清一区| 亚洲啪啪综合av一区二区三区| 97久久精品人人澡人人爽| 欧美一区二区三区白人| 国内外精品视频| 欧美三级在线播放| 青青草国产精品97视觉盛宴| 美女黄色成人网| 一个色妞综合视频在线观看| 亚洲经典视频在线观看| 中文字幕一区二区三区蜜月| 欧美日韩一区二区三区免费| 国产欧美视频一区二区三区| 不卡的电影网站| 精品嫩草影院久久| 国产成人在线免费观看| 欧美丰满美乳xxx高潮www| 蜜桃av噜噜一区二区三区小说| 久久综合久久综合这里只有精品| 亚洲成av人片www| 校园激情久久| 天天射综合影视| 久久综合导航| 久久69国产一区二区蜜臀| 欧美日韩国产一区| 国产剧情一区在线| 日韩精品中文字幕在线不卡尤物| 福利电影一区二区三区| 精品99一区二区| 欧美成人蜜桃| 综合久久久久久| 亚洲一区综合| 日韩和欧美的一区| 欧美日韩国产精品自在自线| 国内精品写真在线观看| 4438成人网| kk眼镜猥琐国模调教系列一区二区| 久久久久久久久久久久久久久99 | 国产精品888| 欧美成人欧美edvon| 99天天综合性| 国产精品久久久一区麻豆最新章节| 激情文学一区| 亚洲丰满少妇videoshd| 色88888久久久久久影院野外| 激情综合五月天| 日韩视频免费观看高清完整版| 成人ar影院免费观看视频| 国产亚洲一二三区| 亚洲日产国产精品| 三级一区在线视频先锋| 欧美精品久久99| 成人av免费在线观看| 国产精品久久久久久亚洲毛片 | 韩国女主播一区| 日韩欧美中文字幕公布| 国产亚洲短视频| 一区二区国产盗摄色噜噜| 欧美一区二区三区公司| 欧美中文字幕一区二区三区亚洲| 石原莉奈一区二区三区在线观看| 亚洲欧美日韩精品久久久久| 视频在线观看91| 久久久亚洲精品石原莉奈| 韩日视频一区| 亚洲成a人v欧美综合天堂| 久久久噜噜噜| 国产成人综合网| 国产精品久久久一本精品 | 天天综合网天天综合色| 日韩一区国产二区欧美三区| 91麻豆文化传媒在线观看| 亚洲另类一区二区| 欧美男男青年gay1069videost| 91碰在线视频| 亚洲福利一区二区| 欧美一级艳片视频免费观看| 国产综合色产| 蜜乳av一区二区| 国产三级精品三级在线专区| 一区二区三区你懂的| 久久99精品国产.久久久久久| 欧美精品一区二区三区一线天视频 | 亚洲第一成人在线| 日韩亚洲欧美高清| 日韩亚洲国产欧美| 激情五月激情综合网| 欧美国产日韩精品免费观看| 色婷婷狠狠综合| 成人黄色大片在线观看| 亚洲女与黑人做爰| 免费在线观看视频一区| 99精品欧美一区二区三区综合在线| 亚洲视频一二区| 欧美日韩国产经典色站一区二区三区 | 一本久道综合久久精品| 精品一区二区成人精品| 国产精品理论在线观看| 欧美在线免费观看视频| 91麻豆国产香蕉久久精品| 亚洲成a人片在线不卡一二三区| 精品美女一区二区| 欧美专区在线| 91首页免费视频| 免费精品视频在线| 国产精品情趣视频| 欧美日韩一区二区三区在线看| 欧美日韩免费观看一区=区三区| 蜜臀av性久久久久蜜臀av麻豆| 国产欧美日韩不卡免费| 欧美私模裸体表演在线观看| 好看不卡的中文字幕| 国产一区二区在线观看免费| 亚洲欧美激情插| 日韩一区二区三区高清免费看看| 亚洲少妇诱惑| 成人av综合在线| 日韩精品91亚洲二区在线观看| 国产欧美一区二区精品性色| 欧美电影一区二区| 在线看片日韩| 菠萝蜜视频在线观看一区| 日韩电影在线观看电影| 国产精品久久久久7777按摩 | 久久久久久久久久久久久久一区| 成人av资源网站| 日韩vs国产vs欧美| 国产精品国产三级国产aⅴ原创| 欧美一区二区久久久| 媚黑女一区二区| 精品成人久久| jizz一区二区| 精彩视频一区二区| 偷窥少妇高潮呻吟av久久免费| 亚洲国产成人自拍| 日韩免费高清电影| 欧美日韩在线一区二区| 性色一区二区| 一区国产精品| 欧美xxx在线观看| 粗大黑人巨茎大战欧美成人| 麻豆精品一区二区av白丝在线| 一区二区三区中文在线| 欧美国产精品中文字幕| 久久人人超碰精品| 91精品中文字幕一区二区三区| 久久亚洲二区| 亚洲一区二区三区免费在线观看 | 久久66热偷产精品| 日本欧洲一区二区| 丝袜脚交一区二区| 亚洲成人一区二区| 1024成人网| 国产精品午夜在线| 国产亚洲1区2区3区| 精品乱人伦一区二区三区| 欧美蜜桃一区二区三区| 久久午夜精品| 美女精品在线观看| 亚洲欧美久久| 国产精品一区二区三区观看| 亚洲视频欧美在线| 欧美午夜免费影院| 91污片在线观看| 99久久99久久免费精品蜜臀| 国产精品一区二区你懂的| 老司机精品视频线观看86| 亚洲高清三级视频| 亚洲国产精品视频| 亚洲一区国产视频| 亚洲乱码精品一二三四区日韩在线| 国产精品美女一区二区在线观看| 久久在线观看免费| 亚洲精品在线一区二区| 337p日本欧洲亚洲大胆精品| 久久综合狠狠综合| 久久久久国产一区二区三区四区| 久久综合中文字幕| 久久―日本道色综合久久| 久久精品人人做| 欧美国产一区在线| 国产精品福利一区二区三区| 国产精品日产欧美久久久久| 国产精品国产三级国产有无不卡| 中文在线一区二区 | 国产精品毛片无遮挡高清| 国产精品色婷婷久久58| 国产精品午夜免费| 亚洲人123区|