SpringBoot集成AOP的代碼示例
1.什么是AOP?
AOP(Aspect Oriented Programming,面向切面編程)是一種編程范式,它旨在將橫切關(guān)注點(diǎn)(cross-cutting concerns)從應(yīng)用程序的業(yè)務(wù)邏輯中分離出來(lái)。橫切關(guān)注點(diǎn)是那些在多個(gè)模塊中重復(fù)出現(xiàn)的功能,如日志記錄、性能監(jiān)控、事務(wù)管理、安全控制等。AOP允許開(kāi)發(fā)者將這些關(guān)注點(diǎn)模塊化,并在不影響應(yīng)用程序主要功能的情況下,將它們編織到應(yīng)用程序的各個(gè)點(diǎn)上。
AOP的關(guān)鍵概念
- 切面(Aspect):封裝了橫切關(guān)注點(diǎn)的模塊。它描述了要執(zhí)行的附加行為以及該行為應(yīng)該被應(yīng)用到哪些連接點(diǎn)上。
- 連接點(diǎn)(Joinpoint):程序執(zhí)行過(guò)程中的某個(gè)點(diǎn),如方法調(diào)用或異常拋出。
- 通知(Advice):切面在特定的連接點(diǎn)上執(zhí)行的動(dòng)作,如“before”、“after”、“around”等。
- 切入點(diǎn)(Pointcut):匹配連接點(diǎn)的表達(dá)式,定義了切面的哪個(gè)部分會(huì)被應(yīng)用到哪些連接點(diǎn)上。
- 目標(biāo)對(duì)象(Target Object):被一個(gè)或多個(gè)切面所通知的對(duì)象。
- 代理(Proxy):由AOP框架創(chuàng)建的對(duì)象,用來(lái)攔截目標(biāo)對(duì)象上的方法調(diào)用。
AOP的實(shí)現(xiàn)方式
AOP可以通過(guò)以下幾種方式實(shí)現(xiàn):
- 基于代理的AOP:
- JDK動(dòng)態(tài)代理:適用于實(shí)現(xiàn)接口的情況,利用反射機(jī)制生成代理類。
- CGLIB:使用字節(jié)碼技術(shù)生成子類,適用于未實(shí)現(xiàn)接口的情況。
- 基于字節(jié)碼操作的AOP:
- AspectJ:在編譯期或運(yùn)行期通過(guò)修改字節(jié)碼來(lái)實(shí)現(xiàn)切面的編織,可以更細(xì)粒度地控制切面的織入。
- 聲明式AOP:
- Spring AOP:使用XML配置或注解(如
@Aspect
、@Before
、@After
、@Around
等)來(lái)定義切面和切入點(diǎn),然后在運(yùn)行時(shí)通過(guò)動(dòng)態(tài)代理實(shí)現(xiàn)切面的編織。
- Spring AOP:使用XML配置或注解(如
實(shí)現(xiàn)AOP的關(guān)鍵技術(shù)
- 動(dòng)態(tài)代理:在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建代理對(duì)象,代理對(duì)象在調(diào)用目標(biāo)方法前后可以執(zhí)行額外的操作。
- 字節(jié)碼操作庫(kù):如ASM、ByteBuddy等,用于生成或修改字節(jié)碼,實(shí)現(xiàn)在類的加載之前或運(yùn)行時(shí)修改類的行為。
- 元數(shù)據(jù)驅(qū)動(dòng):使用注解或XML配置來(lái)定義切面、切入點(diǎn)和通知,便于配置和管理AOP的規(guī)則。
AOP的主要優(yōu)點(diǎn)是能夠減少業(yè)務(wù)邏輯中的重復(fù)代碼,提高代碼的模塊化程度,使得關(guān)注點(diǎn)更加集中,同時(shí)也提高了代碼的可維護(hù)性和可讀性。在實(shí)際應(yīng)用中,AOP經(jīng)常被用于企業(yè)級(jí)應(yīng)用開(kāi)發(fā),如在Spring框架中廣泛使用。
2.代碼工程
實(shí)驗(yàn)?zāi)繕?biāo)
采用@aspect注解來(lái)實(shí)現(xiàn)aop
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>springboot-demo</artifactId> <groupId>com.et</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>aspect</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency> </dependencies> </project>
controller
package com.et.aspect.controller; import com.et.aspect.service.TestService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; @RestController public class HelloWorldController { @Autowired TestService testService; @RequestMapping("/hello") public Map<String, Object> showHelloWorld(){ Map<String, Object> map = new HashMap<>(); String str= testService.sayHello("liming"); map.put("msg",str); return map; } }
service
package com.et.aspect.service; public interface TestService { public String sayHello(String name) ; } package com.et.aspect.service.impl; import com.et.aspect.service.TestService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; /** * @author liuhaihua * @version 1.0 * @ClassName TestServiceImpl * @Description todo * @date 2024/09/05/ 9:21 */ @Service @Slf4j public class TestServiceImpl implements TestService { @Override public String sayHello(String name) { String sss="hello,"+name; log.info(sss); return sss; } }
aspect
@Aspect:作用是把當(dāng)前類標(biāo)識(shí)為一個(gè)切面供容器讀取
@Pointcut:定義切入點(diǎn),Pointcut是植入Advice的觸發(fā)條件。 每個(gè)Pointcut的定義包括2部分,一是表達(dá)式,二是方法簽名。方法簽名必須是 public及void型。 可以將Pointcut中的方法看作是一個(gè)被Advice引用的助記符,因?yàn)楸磉_(dá)式不直觀,因此我們可以通過(guò)方法簽名的方式為 此表達(dá)式命名。 因此Pointcut中的方法只需要方法簽名,而不需要在方法體內(nèi)編寫實(shí)際代碼。
@Around:環(huán)繞增強(qiáng),相當(dāng)于MethodInterceptor(方法攔截器)
@AfterReturning:后置增強(qiáng),相當(dāng)于AfterReturningAdvice,方法正常退出時(shí)執(zhí)行
@Before:標(biāo)識(shí)一個(gè)前置增強(qiáng)方法,相當(dāng)于BeforeAdvice的功能,相似功能的還有
@AfterThrowing:異常拋出增強(qiáng),相當(dāng)于ThrowsAdvice(異常通知)
@After: final增強(qiáng),不管是拋出異常或者正常退出都會(huì)執(zhí)行
@Pointcut("execution(* com.et.aspect.service..*.*(..))") public void aopPoint() { } @Before("aopPoint()") public void doBefore(JoinPoint point) throws Throwable { log.info("before ...."); } @After("aopPoint()") public void doAfter(JoinPoint point) throws Throwable { log.info("after ...."); }
以上只是一些關(guān)鍵代碼,所有代碼請(qǐng)參見(jiàn)下面代碼倉(cāng)庫(kù)
代碼倉(cāng)庫(kù)
3.測(cè)試
啟動(dòng)Spring Boot應(yīng)用程序
訪問(wèn)http://127.0.0.1:8088/hello
查看日志如下
2024-09-05 21:52:12.926 INFO 51009 --- [nio-8088-exec-1] com.et.aspect.aspect.TaskAspect : before .... 2024-09-05 21:52:12.939 INFO 51009 --- [nio-8088-exec-1] c.e.aspect.service.impl.TestServiceImpl : hello,liming 2024-09-05 21:52:12.939 INFO 51009 --- [nio-8088-exec-1] com.et.aspect.aspect.TaskAspect : after ....
以上就是Spring Boot集成AOP的代碼示例的詳細(xì)內(nèi)容,更多關(guān)于Spring Boot集成AOP的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java中的StampedLock實(shí)現(xiàn)原理詳解
這篇文章主要介紹了Java中的StampedLock實(shí)現(xiàn)原理詳解,ReentrantReadWriteLock采用悲觀讀,第一個(gè)讀線程拿到鎖后,第二個(gè)/第三個(gè)讀線程可以拿到鎖,特別是在讀線程很多,寫線程很少時(shí),需要的朋友可以參考下2024-01-01Java實(shí)現(xiàn)的計(jì)算稀疏矩陣余弦相似度示例
這篇文章主要介紹了Java實(shí)現(xiàn)的計(jì)算稀疏矩陣余弦相似度功能,涉及java基于HashMap的數(shù)值計(jì)算相關(guān)操作技巧,需要的朋友可以參考下2018-07-07Spring\SpringBoot配置連接數(shù)據(jù)庫(kù)的方法
最近在學(xué)習(xí)SpringBoot,第一步就是要配置數(shù)據(jù)庫(kù),本文詳細(xì)的介紹了Spring\SpringBoot配置連接數(shù)據(jù)庫(kù)的方法,有需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-06-06Spring中網(wǎng)絡(luò)請(qǐng)求客戶端WebClient的使用詳解
作為替代,Spring 官方已在 Spring 5 中引入了 WebClient 作為非阻塞式 Reactive HTTP 客戶端,本文將通過(guò)樣例演示如何使用 WebClient,希望對(duì)大家有所幫助2024-04-04SpringBoot2.1.4中的錯(cuò)誤處理機(jī)制
這篇文章主要介紹了SpringBoot2.1.4中的錯(cuò)誤處理機(jī)制,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10基于String和List<String>間的相互轉(zhuǎn)換方式
這篇文章主要介紹了基于String和List間的相互轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05