SpringBoot AOP概念及使用Demo


AOP核心概念
1、橫切關注點

對哪些方法進行攔截,攔截后怎么處理,這些關注點稱之為橫切關注點
2、切面(aspect)-》(通知+切點)

類是對物體特征的抽象,切面就是對橫切關注點的抽象。
通知+切點
意思就是所有要被應用到增強(advice)代碼的地方。(包括方法的方位信息)
3、連接點(joinpoint)-》(被攔截的方法)

被攔截到的點,因為Spring只支持方法類型的連接點,所以在Spring中連接點指的就是被攔截的方法,實際上連接點還可以是字段或者構造器
4、切入點(pointcut)-》(描述攔截那些方法的部分)

對連接點進行攔截的定義
5、通知(advice)-》(攔截后執行自己業務邏輯的那些部分)

所謂通知指的就是指攔截到連接點之后要執行的代碼,通知分為前置、后置、異常、最終、環繞通知五類
這玩意也叫 增強
在邏輯層次上包括了我們抽取的公共邏輯和方位信息。因為Spring只能方法級別的應用AOP,也就是我們常見的before,after,after-returning,after-throwing,around五種,意思就是在方法調用前后,異常時候執行我這段公共邏輯唄。
6、目標對象

代理的目標對象
7、織入(weave)

將切面應用到目標對象並導致代理對象創建的過程。
比如根據Advice中的方位信息在指定切點的方法前后,執行增強。這個過程Spring 替我們做好了。利用的是CGLIB動態代理技術。
8、引入(introduction)

在不修改代碼的前提下,引入可以在運行期為類動態地添加一些方法或字段
圖解

上面那一堆看不懂對嗎? 我也不太懂。
來看張圖

 

好了,現在我們直接看代碼,簡單的使用如下:

引入pom

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.8</version><!--$NO-MVN-MAN-VER$-->
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.2</version><!--$NO-MVN-MAN-VER$-->
        </dependency>
        
        <!-- AspectJ -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.2</version><!--$NO-MVN-MAN-VER$-->
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version><!--$NO-MVN-MAN-VER$-->
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>

    </dependencies>

 

創建DTO對象

package com.szl.demo.common.dto;

import lombok.Data;

@Data
public class AccountDto {
    private String accountNo;
    private String accountName;
    private Double balance;
}

 

創建service和service實現類

package com.szl.demo.service;

import com.szl.demo.common.dto.AccountDto;

public interface DemoService {
    
    public AccountDto getUserAccount();
    
}
package com.szl.demo.service.impl;

import org.springframework.stereotype.Service;
import com.szl.demo.common.dto.AccountDto;
import com.szl.demo.service.DemoService;

@Service("demoService")
public class DemoServiceImpl implements DemoService {
    
    public AccountDto getUserAccount() {
        AccountDto dto = new AccountDto();
        dto.setAccountNo("22133232001");
        dto.setAccountName("XXX");
        dto.setBalance(3000D);
        return dto;
    }
}

 

創建controller

package com.szl.demo.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.szl.demo.common.dto.AccountDto;
import com.szl.demo.service.DemoService;

@Controller
public class DemoController {
    @Autowired
    private DemoService demoService;
    
    /**
     * @param request
     * @param response
     * @param body          這個是請求body體
     * @param nickName      這個是post參數
     * @param birthday      這個是post參數
     * @return
     */ @ResponseBody
    @RequestMapping(value = "/testAopDemo", method = RequestMethod.POST,
            consumes = "application/json",
            produces = "application/json;charset=UTF-8")
    public AccountDto testAopDemo(HttpServletRequest request, HttpServletResponse response,
            @RequestBody String body,
            @RequestParam("nickName") String nickName,
            @RequestParam("birthday") String birthday) {
        log.info("controller層 請求body內容: " + body);
        log.info("controller層 請求參數nickName內容: " + nickName);
        log.info("controller層 請求參數birthday內容: " + birthday);
        return demoService.getUserAccount();
    } }

 

以上工作全部做完后,現在我們創建AOP核心代碼塊

package com.szl.demo.common.aop;

import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import lombok.extern.slf4j.Slf4j;

/**
 * @author Jimmy Shan
 * @desc 創建AOP 切面記錄controller的日志記錄
 *       @Slf4j 必須結合lombok一起使用,否則無效
 */
@Slf4j
@Aspect
@Component
public class WebLogAcpect {
// 用於記錄每個controller執行的耗時時間,毫秒級
private ThreadLocal<Long> timeLocal = new ThreadLocal<>();
/** * 定義切入點,切入點為com.example.aop下的所有函數 */ @Pointcut("execution(public * com.szl.demo.controller.*.*(..))") public void webLog(){} /** * @param joinPoint * @throws Throwable * @desc 前置通知:在連接點之前執行的通知 */    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        timeLocal.set(startTime);// 記錄開始時間

        // 接收到請求,記錄請求內容
        ServletRequestAttributes attributes = (ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        
        // 記錄下請求內容
        log.info("URL : " + request.getRequestURL().toString());
        log.info("HTTP_METHOD : " + request.getMethod());
        log.info("IP : " + request.getRemoteAddr());
        log.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
        
        //獲取請求參數信息 和 requestBody數據
        List<String> paramList = new ArrayList<>();
        Object[] objArr = joinPoint.getArgs();
        for (int i = 0; i < objArr.length; i++) {
             if (objArr[i] instanceof String) {
                 paramList.add(String.valueOf(objArr[i]));
             }
        }
        log.info("AOP獲取參數內容為: " + String.join("###", paramList));
    }
/** * @param ret * @throws Throwable * @desc 處理完成請求,返回的信息 */    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        log.info("返回的內容: " + ret);
        log.info("耗時: {} 毫秒", (System.currentTimeMillis() - timeLocal.get().longValue()));
        timeLocal.remove();
    } }

 

OK,到此我們的AOP就可以正常的工作了,我們來看一下效果,控制台日志信息輸出如下:

00:33:37.167 [http-nio-8081-exec-1] INFO   - Initializing Spring DispatcherServlet 'dispatcherServlet'
00:33:37.167 [http-nio-8081-exec-1] INFO   - Initializing Servlet 'dispatcherServlet'
00:33:37.171 [http-nio-8081-exec-1] INFO   - Completed initialization in 2 ms
00:33:37.218 [http-nio-8081-exec-1] INFO   - URL : http://127.0.0.1:8081/testAopDemo
00:33:37.218 [http-nio-8081-exec-1] INFO   - HTTP_METHOD : POST
00:33:37.218 [http-nio-8081-exec-1] INFO   - IP : 127.0.0.1
00:33:37.218 [http-nio-8081-exec-1] INFO   - CLASS_METHOD : com.szl.demo.controller.DemoController.testAopDemo
00:33:37.218 [http-nio-8081-exec-1] INFO   - ARGS : [org.apache.catalina.connector.RequestFacade@69bd93bb, org.apache.catalina.connector.ResponseFacade@5a33b12, {"info2":"haha", "name":"Jackson"}, 百里守約, 2019-06-05]
00:33:37.218 [http-nio-8081-exec-1] INFO   - AOP獲取參數內容為: {"info2":"haha", "name":"Jackson"}###百里守約###2019-06-05
00:33:37.234 [http-nio-8081-exec-1] INFO   - controller層 請求body內容: {"info2":"haha", "name":"Jackson"}
00:33:37.234 [http-nio-8081-exec-1] INFO   - controller層 請求參數nickName內容: 百里守約
00:33:37.234 [http-nio-8081-exec-1] INFO   - controller層 請求參數birthday內容: 2019-06-05
00:33:37.234 [http-nio-8081-exec-1] INFO   - 返回的內容: AccountDto(accountNo=22133232001, accountName=XXX, balance=3000.0)
00:33:37.234 [http-nio-8081-exec-1] INFO   - 耗時: 16 毫秒

藍色字體部分就是 AOP 和 controller 獲取參數的值信息。

 

 轉自:https://www.cnblogs.com/lic309/p/4079194.html

         https://blog.csdn.net/lmb55/article/details/82470388


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM