<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring Boot AOP 掃盲

          共 4900字,需瀏覽 10分鐘

           ·

          2022-02-21 22:25

          大家好,我是二哥呀。AOP 是 Spring 體系中非常重要的兩個概念之一(另外一個是 IoC),今天這篇文章就來帶大家通過實戰(zhàn)的方式,在編程貓 SpringBoot 項目中使用 AOP 技術(shù)為 controller 層添加一個切面來實現(xiàn)接口訪問的統(tǒng)一日志記錄。

          一、關(guān)于 AOP

          AOP,也就是 Aspect-oriented Programming,譯為面向切面編程,是計算機科學(xué)中的一個設(shè)計思想,旨在通過切面技術(shù)為業(yè)務(wù)主體增加額外的通知(Advice),從而對聲明為“切點”(Pointcut)的代碼塊進行統(tǒng)一管理和裝飾。

          這種思想非常適用于,將那些與核心業(yè)務(wù)不那么密切關(guān)聯(lián)的功能添加到程序中,就好比我們今天的主題——日志功能,就是一個典型的案例。

          AOP 是對面向?qū)ο缶幊蹋∣bject-oriented Programming,俗稱 OOP)的一種補充,OOP 的核心單元是類(class),而 AOP 的核心單元是切面(Aspect)。利用 AOP 可以對業(yè)務(wù)邏輯的各個部分進行隔離,從而降低耦合度,提高程序的可重用性,同時也提高了開發(fā)效率。

          我們可以簡單的把 AOP 理解為貫穿于方法之中,在方法執(zhí)行前、執(zhí)行時、執(zhí)行后、返回值后、異常后要執(zhí)行的操作。

          二、AOP 的相關(guān)術(shù)語

          來看下面這幅圖,這是一個 AOP 的模型圖,就是在某些方法執(zhí)行前后執(zhí)行一些通用的操作,并且這些操作不會影響程序本身的運行。

          我們了解下 AOP 涉及到的 5 個關(guān)鍵術(shù)語:

          1)橫切關(guān)注點,從每個方法中抽取出來的同一類非核心業(yè)務(wù)

          2)切面(Aspect),對橫切關(guān)注點進行封裝的類,每個關(guān)注點體現(xiàn)為一個通知方法;通常使用 @Aspect 注解來定義切面。

          3)通知(Advice),切面必須要完成的各個具體工作,比如我們的日志切面需要記錄接口調(diào)用前后的時長,就需要在調(diào)用接口前后記錄時間,再取差值。通知的方式有五種:

          • @Before:通知方法會在目標方法調(diào)用之前執(zhí)行
          • @After:通知方法會在目標方法調(diào)用后執(zhí)行
          • @AfterReturning:通知方法會在目標方法返回后執(zhí)行
          • @AfterThrowing:通知方法會在目標方法拋出異常后執(zhí)行
          • @Around:把整個目標方法包裹起來,在被調(diào)用前和調(diào)用之后分別執(zhí)行通知方法

          4)連接點(JoinPoint),通知應(yīng)用的時機,比如接口方法被調(diào)用時就是日志切面的連接點。

          5)切點(Pointcut),通知功能被應(yīng)用的范圍,比如本篇日志切面的應(yīng)用范圍是所有 controller 的接口。通常使用 @Pointcut 注解來定義切點表達式。

          切入點表達式的語法格式規(guī)范如下所示:

          execution(modifiers-pattern??ret-type-pattern?declaring-type-pattern?
          ????name-pattern(param-pattern)
          ????????????????throws-pattern?)
          • modifiers-pattern? 為訪問權(quán)限修飾符
          • ret-type-pattern 為返回類型,通常用 * 來表示任意返回類型
          • declaring-type-pattern? 為包名
          • name-pattern 為方法名,可以使用 * 來表示所有,或者 set* 來表示所有以 set 開頭的類名
          • param-pattern) 為參數(shù)類型,多個參數(shù)可以用 , 隔開,各個參與也可以使用 * 來表示所有類型的參數(shù),還可以使用 (..) 表示零個或者任意參數(shù)
          • throws-pattern? 為異常類型
          • ? 表示前面的為可選項

          舉個例子:

          @Pointcut("execution(public?*?com.codingmore.controller.*.*(..))")

          表示 com.codingmore.controller 包下的所有 public 方法都要應(yīng)用切面的通知。

          三、實操 AOP 記錄接口訪問日志

          第一步,在 Spring Boot 項目的 pom.xml 文件中添加 spring-boot-starter-aop 依賴。


          ????org.springframework.boot
          ????spring-boot-starter-aop

          第二步,添加日志信息封裝類 WebLog,用于記錄什么樣的操作、操作的人是誰、開始時間、花費的時間、操作的路徑、操作的方法名、操作主機的 IP、請求參數(shù)、返回結(jié)果等。

          /**
          ?*?Controller層的日志封裝類
          ?*?Created?by?macro?on?2018/4/26.
          ?*/

          public?class?WebLog?{
          ????private?String?description;
          ????private?String?username;
          ????private?Long?startTime;
          ????private?Integer?spendTime;
          ????private?String?basePath;
          ????private?String?uri;
          ????private?String?url;
          ????private?String?method;
          ????private?String?ip;
          ????private?Object?parameter;
          ????private?Object?result;
          ????//省略了getter,setter方法
          }

          第三步,添加統(tǒng)一日志處理切面 WebLogAspect。

          /**
          ?*?統(tǒng)一日志處理切面
          ?*?Created?by?石磊
          ?*/

          @Aspect
          @Component
          @Order(1)
          public?class?WebLogAspect?{
          ????private?static?final?Logger?LOGGER?=?LoggerFactory.getLogger(WebLogAspect.class);

          ????@Pointcut("execution(public?*?com.codingmore.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();
          ????????//獲取當(dāng)前請求對象
          ????????ServletRequestAttributes?attributes?=?(ServletRequestAttributes)?RequestContextHolder.getRequestAttributes();
          ????????HttpServletRequest?request?=?attributes.getRequest();
          ????????//記錄請求信息(通過Logstash傳入Elasticsearch)
          ????????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?log?=?method.getAnnotation(ApiOperation.class);
          ????????????webLog.setDescription(log.value());
          ????????}
          ????????long?endTime?=?System.currentTimeMillis();
          ????????String?urlStr?=?request.getRequestURL().toString();
          ????????webLog.setBasePath(StrUtil.removeSuffix(urlStr,?URLUtil.url(urlStr).getPath()));
          ????????webLog.setIp(request.getRemoteUser());
          ????????Map?logMap?=?new?HashMap<>();
          ????????logMap.put("spendTime",webLog.getSpendTime());
          ????????logMap.put("description",webLog.getDescription());
          ????????LOGGER.info("{}",?JSONUtil.parse(webLog));
          ????????return?result;
          ????}
          }

          第四步,運行項目,并對 controller 下的某個控制器進行測試。

          Swagger knife4j 訪問地址:http://localhost:9022/doc.html

          執(zhí)行登錄用戶查詢操作:可以在控制臺可以看到以下日志信息:

          源碼地址:

          https://github.com/itwanger/coding-more

          參考鏈接:

          作者 cxuan:https://www.cnblogs.com/cxuanBlog/p/13060510.html
          灰小猿:https://bbs.huaweicloud.com/blogs/289045
          山高我為峰:https://www.cnblogs.com/liaojie970/p/7883687.html
          macrozheng:https://github.com/macrozheng/mall


          本篇已收錄至 GitHub 上星標 1.6k+ star 的開源專欄《Java 程序員進階之路》,該專欄風(fēng)趣幽默、通俗易懂,對 Java 愛好者極度友好和舒適??,內(nèi)容包括但不限于 Java 基礎(chǔ)、Java 集合框架、Java IO、Java 并發(fā)編程、Java 虛擬機、Java 企業(yè)級開發(fā)(Git、SSM、Spring Boot)等核心知識點。

          https://github.com/itwanger/toBeBetterJavaer

          star 了這個倉庫就等于你擁有了成為了一名優(yōu)秀 Java 工程師的潛力。

          推薦閱讀

          瀏覽 46
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  大香蕉在线伊 | 大鸡吧插嫩逼视频网站免费 | 日韩精品AV在线观看 | 亚洲日韩中文字幕视频在线 | 九九九成人 |