springboot引入AOP


AOP是Aspect Oriented Programming的縮寫,意為面向切面編程。通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。AOP是spring框架的一個重要內容,她通過對既有程序定義一個切入點(pointcut),然后在切入點前后切入不同的執行任務,常見使用場景有:打開/關閉數據庫連接、打開/關閉事物、記錄日志等等。基於AOP不會破壞原來的程序邏輯,因此她可以很好地對業務邏輯的各個不分進行抽離,從而使得業務邏輯各個部分的耦合度降低,提高程序的復用性,同時提高開發效率。

下面介紹下,aop的簡單使用——統一處理web請求的日志:

1、在項目中引入AOP

引入方式同其他模塊,在pom.xml中添加AOP依賴

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

在引入AOP模塊之后,一般來講,不用去做其他配置。spring.aop.auto屬性默認是開啟的,也就是說只要引入了AOP的依賴之后,默認已經增加了@EnableAspectJAutoProxy

2、創建一個簡單的web請求處理

引入web模塊

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

 實現一個簡單的web請求處理,見下圖

3、實現web層的日志切面類:WebLogAspect

 

package com.example.demo.web;

import com.sun.istack.internal.logging.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import sun.nio.cs.ext.PCK;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalTime;
import java.util.Arrays;


@Aspect
@Component
public class WebLogAspect {
    private Logger logger = Logger.getLogger(getClass());

    @Pointcut("execution(* com.example.demo.web.*.*(..))")
    public void webLog(){}

    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        System.out.println("before : "+LocalTime.now());
        //接收到請求,記錄請求內容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        //記錄請求內容
        logger.info("URL : "+request.getRequestURL().toString());logger.info("HTTP_METHOD : " + request.getMethod());
        logger.info("IP : " + request.getRemoteAddr());
        logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));

    }

    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable{
        System.out.println("after : "+ LocalTime.now());
        //處理完請求,返回內容
        logger.info("RESPONCE : "+ ret);
    }

}

 

實現AOP的切面主要有一下幾個因素:

  1、使用@Aspect注解將一個Java類定義為切面類

  2、使用@Pointcut定義一個切入點,規則表達式示例如下:

任意公共方法的執行:
    execution(public * *(..))
  任何一個以“set”開始的方法的執行:
    execution(* set*(..))
  AccountService 接口的任意方法的執行:
    execution(* com.xyz.service.AccountService.*(..))
  定義在service包里的任意方法的執行:
    execution(* com.xyz.service.*.*(..))
  定義在service包和所有子包里的任意類的任意方法的執行:
    execution(* com.xyz.service..*.*(..))
  定義在pointcutexp包和所有子包里的JoinPointObjP2類的任意方法的執行:
    execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")

 

   3、根據需要在切入點的不同位置切入指定內容

    使⽤ @Before 在切⼊點開始處切⼊內容
    使⽤ @After 在切⼊點結尾處切⼊內容
    使⽤ @AfterReturning 在切⼊點return內容之后切⼊內容(可以⽤來對處理返回值做⼀些加⼯處理)
    使⽤ @Around 在切⼊點前后切⼊內容,並⾃⼰控制何時執⾏切⼊點⾃身的內容
    使⽤ @AfterThrowing ⽤來處理當切⼊內容部分拋出異常之后的處理邏輯

4、最后,請求localhost:8888/hello?name=Sam

控制台日志:

5、 多個切面的優先級問題

優化:AOP切⾯的優先級
由於通過AOP實現,程序得到了很好的解耦,但是也會帶來⼀些問題,⽐如:我們可能會對Web層做
多個切⾯,校驗⽤戶,校驗頭信息等等,這個時候經常會碰到切⾯的處理順序問題。
所以,我們需要定義每個切⾯的優先級,我們需要 @Order(i) 注解來標識切⾯的優先級。i的值越
⼩,優先級越⾼。假設我們還有⼀個切⾯是 CheckNameAspect ⽤來校驗name必須為didi,我們為其設
置 @Order(10) ,⽽上⽂中WebLogAspect設置為 @Order(5) ,所以WebLogAspect有更⾼的優先
級,這個時候執⾏順序是這樣的:
  在 @Before 中優先執⾏ @Order(5) 的內容,再執⾏ @Order(10) 的內容
  在 @After 和 @AfterReturning 中優先執⾏ @Order(10) 的內容,再執⾏ @Order(5) 的內容

所以我們可以這樣⼦總結:
  在切⼊點前的操作,按order的值由⼩到⼤執⾏
  在切⼊點后的操作,按order的值由⼤到⼩執⾏


免責聲明!

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



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