Spring AOP注解實(shí)戰(zhàn)指南
1. 背景
在現(xiàn)代軟件開(kāi)發(fā)中,面向切面編程(AOP)是一種強(qiáng)大的編程范式,允許開(kāi)發(fā)者跨越應(yīng)用程序的多個(gè)部分定義橫切關(guān)注點(diǎn)(如日志記錄、事務(wù)管理等)。本文將介紹如何在Spring框架中通過(guò)AspectJ注解以及對(duì)應(yīng)的XML配置來(lái)實(shí)現(xiàn)AOP,在不改變主業(yè)務(wù)邏輯的情況下增強(qiáng)應(yīng)用程序的功能。
2. 基于AspectJ注解來(lái)實(shí)現(xiàn)AOP
對(duì)于一個(gè)使用Maven的Spring項(xiàng)目,需要在pom.xml中添加以下依賴(lài):
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.10</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
</dependencies>
確保版本號(hào)與使用的Spring版本相匹配,可以自行調(diào)整。
創(chuàng)建業(yè)務(wù)邏輯接口MyService:
package com.example.demo.aop;
public interface MyService {
void performAction();
}
創(chuàng)建業(yè)務(wù)邏輯類(lèi)MyServiceImpl.java:
package com.example.demo.aop;
import org.springframework.stereotype.Service;
@Service
public class MyServiceImpl implements MyService {
@Override
public void performAction() {
System.out.println("Performing an action in MyService");
}
}
定義切面
創(chuàng)建切面類(lèi)MyAspect.java,并使用注解定義切面和通知:
package com.example.demo.aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAspect {
@Before("execution(* com.example.demo.aop.MyServiceImpl.performAction(..))")
public void logBeforeAction() {
System.out.println("Before performing action");
}
}
@Aspect注解是用來(lái)標(biāo)識(shí)一個(gè)類(lèi)作為AspectJ切面的一種方式,這在基于注解的AOP配置中是必需的。它相當(dāng)于XML配置中定義切面的方式,但使用注解可以更加直觀和便捷地在類(lèi)級(jí)別上聲明切面,而無(wú)需繁瑣的XML配置。
配置Spring以啟用注解和AOP
創(chuàng)建一個(gè)Java配置類(lèi)來(lái)代替XML配置,使用@Configuration注解標(biāo)記為配置類(lèi),并通過(guò)@ComponentScan注解來(lái)啟用組件掃描,通過(guò)@EnableAspectJAutoProxy啟用AspectJ自動(dòng)代理:
package com.example.demo.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan("com.example")
@EnableAspectJAutoProxy
public class AppConfig {
}
@EnableAspectJAutoProxy注解在Spring中用于啟用對(duì)AspectJ風(fēng)格的切面的支持。它告訴Spring框架去尋找?guī)в?code>@Aspect注解的類(lèi),并將它們注冊(cè)為Spring應(yīng)用上下文中的切面,以便在運(yùn)行時(shí)通過(guò)代理方式應(yīng)用這些切面定義的通知(Advice)和切點(diǎn)(Pointcuts)。
如果不寫(xiě)@EnableAspectJAutoProxy,Spring將不會(huì)自動(dòng)處理@Aspect注解定義的切面,則定義的那些前置通知(@Before)、后置通知(@After、@AfterReturning、@AfterThrowing)和環(huán)繞通知(@Around)將不會(huì)被自動(dòng)應(yīng)用到目標(biāo)方法上。這意味著定義的AOP邏輯不會(huì)被執(zhí)行,失去了AOP帶來(lái)的功能增強(qiáng)。
@Before 注解定義了一個(gè)前置通知(Advice),它會(huì)在指定方法執(zhí)行之前運(yùn)行。切點(diǎn)表達(dá)式execution(* com.example.demo.aop.MyServiceImpl.performAction(..))精確地定義了這些連接點(diǎn)的位置。在這個(gè)例子中,切點(diǎn)表達(dá)式指定了MyServiceImpl類(lèi)中的performAction方法作為連接點(diǎn),而@Before注解標(biāo)識(shí)的方法(logBeforeAction)將在這個(gè)連接點(diǎn)之前執(zhí)行,即logBeforeAction方法(前置通知)會(huì)在performAction執(zhí)行之前被執(zhí)行。
創(chuàng)建主類(lèi)和測(cè)試AOP功能
主程序如下:
package com.example.demo;
import com.example.demo.aop.MyService;
import com.example.demo.config.AppConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class DemoApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyService service = context.getBean(MyService.class);
service.performAction();
}
}
運(yùn)行結(jié)果如下:

3. XML實(shí)現(xiàn)和注解實(shí)現(xiàn)AOP的代碼對(duì)比
對(duì)于上面的代碼,我們將原有基于注解的AOP配置改寫(xiě)為完全基于XML的形式,方便大家對(duì)比。首先需要移除切面類(lèi)和業(yè)務(wù)邏輯類(lèi)上的所有Spring相關(guān)注解,然后在XML文件中配置相應(yīng)的bean和AOP邏輯。
移除注解
首先,我們移除業(yè)務(wù)邏輯類(lèi)和切面類(lèi)上的所有注解。
MyService.java (無(wú)變化,接口保持原樣):
package com.example.demo.aop;
public interface MyService {
void performAction();
}
MyServiceImpl.java (移除@Service注解):
package com.example.demo.aop;
public class MyServiceImpl implements MyService {
@Override
public void performAction() {
System.out.println("Performing an action in MyService");
}
}
MyAspect.java (移除@Aspect和@Component注解,同時(shí)去掉方法上的@Before注解):
package com.example.demo.aop;
public class MyAspect {
public void logBeforeAction() {
System.out.println("Before performing action");
}
}
XML配置
接下來(lái),刪除AppConfig配置類(lèi),在Spring的XML配置文件中定義beans和AOP配置。
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 定義業(yè)務(wù)邏輯bean -->
<bean id="myService" class="com.example.demo.aop.MyServiceImpl"/>
<!-- 定義切面 -->
<bean id="myAspect" class="com.example.demo.aop.MyAspect"/>
<!-- AOP配置 -->
<aop:config>
<aop:aspect id="aspect" ref="myAspect">
<aop:pointcut id="serviceOperation" expression="execution(* com.example.demo.aop.MyService.performAction(..))"/>
<aop:before pointcut-ref="serviceOperation" method="logBeforeAction"/>
</aop:aspect>
</aop:config>
</beans>
在這個(gè)XML配置中,我們手動(dòng)注冊(cè)了MyServiceImpl和MyAspect作為beans,并通過(guò)<aop:config>元素定義了AOP邏輯。我們創(chuàng)建了一個(gè)切點(diǎn)serviceOperation,用于匹配MyService.performAction(..)方法的執(zhí)行,并定義了一個(gè)前置通知,當(dāng)匹配的方法被調(diào)用時(shí),MyAspect的logBeforeAction方法將被執(zhí)行。
主類(lèi)和測(cè)試AOP功能
主類(lèi)DemoApplication的代碼不需要改變,只是在創(chuàng)建ApplicationContext時(shí)使用XML配置文件而不是Java配置類(lèi):
package com.example.demo;
import com.example.demo.aop.MyService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class DemoApplication {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyService service = context.getBean(MyService.class);
service.performAction();
}
}
運(yùn)行結(jié)果是一樣的

4. AOP通知講解
在Spring AOP中,通知(Advice)定義了切面(Aspect)在目標(biāo)方法調(diào)用過(guò)程中的具體行為。Spring AOP支持五種類(lèi)型的通知,它們分別是:前置通知(Before)、后置通知(After)、返回通知(After Returning)、異常通知(After Throwing)和環(huán)繞通知(Around)。通過(guò)使用這些通知,開(kāi)發(fā)者可以在目標(biāo)方法的不同執(zhí)行點(diǎn)插入自定義的邏輯。
@Before(前置通知)
前置通知是在目標(biāo)方法執(zhí)行之前執(zhí)行的通知,通常用于執(zhí)行一些預(yù)處理任務(wù),如日志記錄、安全檢查等。
@Before("execution(* com.example.demo.aop.MyServiceImpl.performAction(..))")
public void logBeforeAction() {
System.out.println("Before performing action");
}
@AfterReturning(返回通知)
返回通知在目標(biāo)方法成功執(zhí)行之后執(zhí)行,可以訪問(wèn)方法的返回值。
@AfterReturning(pointcut = "execution(* com.example.demo.aop.MyServiceImpl.performAction(..))", returning = "result")
public void logAfterReturning(Object result) {
System.out.println("Method returned value is : " + result);
}
這里在@AfterReturning注解中指定returning = "result"時(shí),Spring AOP框架將目標(biāo)方法的返回值傳遞給切面方法的名為result的參數(shù),因此,切面方法需要有一個(gè)與之匹配的參數(shù),類(lèi)型兼容目標(biāo)方法的返回類(lèi)型。如果兩者不匹配,Spring在啟動(dòng)時(shí)會(huì)拋出異常,因?yàn)樗鼰o(wú)法將返回值綁定到切面方法的參數(shù)。
@AfterThrowing(異常通知)
異常通知在目標(biāo)方法拋出異常時(shí)執(zhí)行,允許訪問(wèn)拋出的異常。
@AfterThrowing(pointcut = "execution(* com.example.demo.aop.MyServiceImpl.performAction(..))", throwing = "ex")
public void logAfterThrowing(JoinPoint joinPoint, Throwable ex) {
String methodName = joinPoint.getSignature().getName();
System.out.println("@AfterThrowing: Exception in method: " + methodName + "; Exception: " + ex.toString());
}
在@AfterThrowing注解的方法中包含JoinPoint參數(shù)是可選的,當(dāng)想知道哪個(gè)連接點(diǎn)(即方法)引發(fā)了異常的詳細(xì)信息時(shí)非常有用,假設(shè)有多個(gè)方法可能拋出相同類(lèi)型的異常,而我們想在日志中明確指出是哪個(gè)方法引發(fā)了異常。通過(guò)訪問(wèn)JoinPoint提供的信息,可以記錄下引發(fā)異常的方法名稱(chēng)和其他上下文信息,從而使得日志更加清晰和有用。
@After(后置通知)
后置通知在目標(biāo)方法執(zhí)行之后執(zhí)行,無(wú)論方法執(zhí)行是否成功,即便發(fā)生異常,仍然會(huì)執(zhí)行。它類(lèi)似于finally塊。
@After("execution(* com.example.demo.aop.MyServiceImpl.performAction(..))")
public void logAfter() {
System.out.println("After performing action");
}
@Around(環(huán)繞通知)
環(huán)繞通知圍繞目標(biāo)方法執(zhí)行,可以在方法調(diào)用前后執(zhí)行自定義邏輯,同時(shí)決定是否繼續(xù)執(zhí)行目標(biāo)方法。環(huán)繞通知提供了最大的靈活性和控制力。
@Around("execution(* com.example.demo.aop.MyServiceImpl.performAction(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Before method execution");
Object result = joinPoint.proceed(); // 繼續(xù)執(zhí)行目標(biāo)方法
System.out.println("After method execution");
return result;
}
接下來(lái),我們來(lái)演示一下,全部代碼如下:
服務(wù)接口(MyService.java):
package com.example.demo.aop;
public interface MyService {
String performAction(String input);
}
服務(wù)實(shí)現(xiàn)(MyServiceImpl.java):
修改performAction方法,使其在接收到特定輸入時(shí)拋出異常
package com.example.demo.aop;
import org.springframework.stereotype.Service;
@Service
public class MyServiceImpl implements MyService {
@Override
public String performAction(String input) {
System.out.println("Performing action with: " + input);
if ("error".equals(input)) {
throw new RuntimeException("Simulated error");
}
return "Processed " + input;
}
}
完整的切面類(lèi)(包含所有通知類(lèi)型)
切面類(lèi)(MyAspect.java) - 保持不變,確保包含所有類(lèi)型的通知:
package com.example.demo.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAspect {
@Before("execution(* com.example.demo.aop.MyService.performAction(..))")
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("@Before: Before calling performAction");
}
@After("execution(* com.example.demo.aop.MyService.performAction(..))")
public void afterAdvice(JoinPoint joinPoint) {
System.out.println("@After: After calling performAction");
}
@AfterReturning(pointcut = "execution(* com.example.demo.aop.MyService.performAction(..))", returning = "result")
public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
System.out.println("@AfterReturning: Method returned value is : " + result);
}
@AfterThrowing(pointcut = "execution(* com.example.demo.aop.MyService.performAction(..))", throwing = "ex")
public void afterThrowingAdvice(JoinPoint joinPoint, Throwable ex) {
String methodName = joinPoint.getSignature().getName();
System.out.println("@AfterThrowing: Exception in method: " + methodName + "; Exception: " + ex.toString());
}
@Around("execution(* com.example.demo.aop.MyService.performAction(..))")
public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("@Around: Before method execution");
Object result = null;
try {
result = proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
// 如果執(zhí)行方法出現(xiàn)異常,打印這里
System.out.println("@Around: Exception in method execution");
throw throwable;
}
// 如果執(zhí)行方法正常,打印這里
System.out.println("@Around: After method execution");
return result;
}
}
這里要強(qiáng)調(diào)幾點(diǎn):
@Around環(huán)繞通知常見(jiàn)用例是異常捕獲和重新拋出。在這個(gè)例子中,我們通過(guò)ProceedingJoinPoint的proceed()方法調(diào)用目標(biāo)方法。如果目標(biāo)方法執(zhí)行成功,記錄執(zhí)行后的消息并返回結(jié)果。如果在執(zhí)行過(guò)程中發(fā)生異常,在控制臺(tái)上打印出異常信息,然后重新拋出這個(gè)異常。這樣做可以確保異常不會(huì)被吞沒(méi),而是可以被上層調(diào)用者捕獲或由其他異常通知處理。
@AfterThrowing注解標(biāo)明這個(gè)通知只有在目標(biāo)方法因?yàn)楫惓6K止時(shí)才會(huì)執(zhí)行。throwing屬性指定了綁定到通知方法參數(shù)上的異常對(duì)象的名稱(chēng)。這樣當(dāng)異常發(fā)生時(shí),異常對(duì)象會(huì)被傳遞到afterThrowingAdvice方法中,方法中可以對(duì)異常進(jìn)行記錄或處理。
@AfterThrowing和@AfterReturning通知不會(huì)在同一個(gè)方法調(diào)用中同時(shí)執(zhí)行。這兩個(gè)通知的觸發(fā)條件是互斥的。@AfterReturning 通知只有在目標(biāo)方法成功執(zhí)行并正常返回后才會(huì)被觸發(fā),這個(gè)通知可以訪問(wèn)方法的返回值。@AfterThrowing 通知只有在目標(biāo)方法拋出異常時(shí)才會(huì)被觸發(fā),這個(gè)通知可以訪問(wèn)拋出的異常對(duì)象。
假設(shè)想要某個(gè)邏輯總是在方法返回時(shí)執(zhí)行,不管是拋出異常還是正常返回,則考慮放在@After或者@Around通知里執(zhí)行。
配置類(lèi)
package com.example.demo.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan("com.example")
@EnableAspectJAutoProxy
public class AppConfig {
}
測(cè)試不同情況
為了測(cè)試所有通知類(lèi)型的觸發(fā),在主類(lèi)中執(zhí)行performAction方法兩次:一次傳入正常參數(shù),一次傳入會(huì)導(dǎo)致異常的參數(shù)。
主程序如下:
package com.example.demo;
import com.example.demo.aop.MyService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class DemoApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyService service = context.getBean(MyService.class);
try {
// 正常情況
System.out.println("Calling performAction with 'test'");
service.performAction("test");
// 異常情況
System.out.println("\nCalling performAction with 'error'");
service.performAction("error");
} catch (Exception e) {
System.out.println("Exception caught in DemoApplication: " + e.getMessage());
}
}
}
在這個(gè)例子中,當(dāng)performAction方法被第二次調(diào)用并傳入"error"作為參數(shù)時(shí),將會(huì)拋出異常,從而觸發(fā)@AfterThrowing通知。
運(yùn)行結(jié)果如下:

5. AOP時(shí)序圖
這里展示在Spring AOP框架中一個(gè)方法調(diào)用的典型處理流程,包括不同類(lèi)型的通知(Advice)的執(zhí)行時(shí)機(jī)。

- 客戶(hù)端調(diào)用方法:
- 客戶(hù)端(
Client)發(fā)起對(duì)某個(gè)方法的調(diào)用。這個(gè)調(diào)用首先被AOP代理(AOP Proxy)接收,這是因?yàn)樵?code>Spring AOP中,代理負(fù)責(zé)在真實(shí)對(duì)象(Target)和外界之間進(jìn)行中介。
- 環(huán)繞通知開(kāi)始 (
@Around):
AOP代理首先調(diào)用切面(Aspect)中定義的環(huán)繞通知的開(kāi)始部分。環(huán)繞通知可以在方法執(zhí)行前后執(zhí)行代碼,并且能決定是否繼續(xù)執(zhí)行方法或直接返回自定義結(jié)果。這里的“開(kāi)始部分”通常包括方法執(zhí)行前的邏輯。
- 前置通知 (
@Before):
- 在目標(biāo)方法執(zhí)行之前,執(zhí)行前置通知。這用于在方法執(zhí)行前執(zhí)行如日志記錄、安全檢查等操作。
- 執(zhí)行目標(biāo)方法:
- 如果環(huán)繞通知和前置通知沒(méi)有中斷執(zhí)行流程,代理會(huì)調(diào)用目標(biāo)對(duì)象(
Target)的實(shí)際方法。
- 方法完成:
- 方法執(zhí)行完成后,控制權(quán)返回到
AOP代理。這里的“完成”可以是成功結(jié)束,也可以是拋出異常。
- 返回通知或異常通知:
- 返回通知 (
@AfterReturning):如果方法成功完成,即沒(méi)有拋出異常,執(zhí)行返回通知。這可以用來(lái)處理方法的返回值或進(jìn)行某些后續(xù)操作。 - 異常通知 (
@AfterThrowing):如果方法執(zhí)行過(guò)程中拋出異常,執(zhí)行異常通知。這通常用于異常記錄或進(jìn)行異常處理。
- 后置通知 (
@After):
- 獨(dú)立于方法執(zhí)行結(jié)果,后置通知總是會(huì)執(zhí)行。這類(lèi)似于在編程中的
finally塊,常用于資源清理。
- 環(huán)繞通知結(jié)束 (
@Around):
- 在所有其他通知執(zhí)行完畢后,環(huán)繞通知的結(jié)束部分被執(zhí)行。這可以用于執(zhí)行清理工作,或者在方法執(zhí)行后修改返回值。
- 返回結(jié)果:
- 最終,
AOP代理將處理的結(jié)果返回給客戶(hù)端。這個(gè)結(jié)果可能是方法的返回值,或者通過(guò)環(huán)繞通知修改后的值,或者是異常通知中處理的結(jié)果。
以上就是Spring AOP注解實(shí)戰(zhàn)指南的詳細(xì)內(nèi)容,更多關(guān)于Spring AOP注解的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- springbootAOP定義切點(diǎn)獲取/修改請(qǐng)求參數(shù)方式
- 使用Spring AOP監(jiān)控指定方法執(zhí)行時(shí)間的代碼詳解
- Spring?AOP中的環(huán)繞通知詳解
- Spring Boot使用AOP在指定方法執(zhí)行完后執(zhí)行異步處理操作
- spring?boot如何通過(guò)自定義注解和AOP攔截指定的請(qǐng)求
- SpringBoot使用AOP實(shí)現(xiàn)統(tǒng)計(jì)全局接口訪問(wèn)次數(shù)詳解
- 詳解Java SpringAOP切面類(lèi)
- Spring AOP快速入門(mén)及開(kāi)發(fā)步驟
相關(guān)文章
SpringBoot整合Swagger頁(yè)面禁止訪問(wèn)swagger-ui.html方式
本文介紹了如何在SpringBoot項(xiàng)目中通過(guò)配置SpringSecurity和創(chuàng)建攔截器來(lái)禁止訪問(wèn)SwaggerUI頁(yè)面,此外,還提供了禁用SwaggerUI和Swagger資源的配置方法,以確保這些端點(diǎn)和頁(yè)面對(duì)外部用戶(hù)不可見(jiàn)或無(wú)法訪問(wèn)2025-02-02
如何使用Spring boot的@Transactional進(jìn)行事務(wù)管理
這篇文章介紹了SpringBoot中使用@Transactional注解進(jìn)行聲明式事務(wù)管理的詳細(xì)信息,包括基本用法、核心配置參數(shù)、關(guān)鍵注意事項(xiàng)、調(diào)試技巧、最佳實(shí)踐以及完整示例,感興趣的朋友一起看看吧2025-02-02
Java根據(jù)實(shí)體生成SQL數(shù)據(jù)庫(kù)表的示例代碼
這篇文章主要來(lái)和大家分享一個(gè)Java實(shí)現(xiàn)根據(jù)實(shí)體生成SQL數(shù)據(jù)庫(kù)表的代碼,文中的實(shí)現(xiàn)代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-07-07
Java JDK動(dòng)態(tài)代理在攔截器和聲明式接口中的應(yīng)用小結(jié)
Java動(dòng)態(tài)代理技術(shù)通過(guò)反射機(jī)制在運(yùn)行時(shí)動(dòng)態(tài)生成代理類(lèi),實(shí)現(xiàn)對(duì)目標(biāo)對(duì)象方法的攔截和增強(qiáng),本文給大家介紹Java JDK動(dòng)態(tài)代理在攔截器和聲明式接口中的應(yīng)用小結(jié),感興趣的朋友跟隨小編一起看看吧2025-01-01
MyBatis-Plus攔截器對(duì)敏感數(shù)據(jù)實(shí)現(xiàn)加密
做課程項(xiàng)目petstore時(shí)遇到需要加密屬性的問(wèn)題,而MyBatis-Plus為開(kāi)發(fā)者提供了攔截器的相關(guān)接口,本文主要介紹通過(guò)MyBatis-Plus的攔截器接口自定義一個(gè)攔截器類(lèi)實(shí)現(xiàn)敏感數(shù)據(jù)如用戶(hù)密碼的加密功能,感興趣的可以了解一下2021-11-11

