該應(yīng)用程序通常是多層開發(fā)的。典型的Java應(yīng)用程序具有以下幾層:
Web層: 它使用REST或Web應(yīng)用程序公開服務(wù)。 業(yè)務(wù)層: 它實(shí)現(xiàn)了應(yīng)用程序的業(yè)務(wù)邏輯。 數(shù)據(jù)層: 它實(shí)現(xiàn)了應(yīng)用程序的持久性邏輯。
每層的職責(zé)不同,但是有一些適用于所有層的常見方面是 日志記錄,安全性,驗(yàn)證,緩存等。這些常見方面被稱為 跨領(lǐng)域關(guān)注點(diǎn)。
如果我們分別在每一層中實(shí)現(xiàn)這些關(guān)注點(diǎn),則代碼將變得更加難以維護(hù)。為了克服這個(gè)問題, 面向方面的編程(AOP)提供了一種解決跨領(lǐng)域問題的解決方案。
將跨領(lǐng)域關(guān)注作為一個(gè)方面。 定義切入點(diǎn)以指示必須在何處應(yīng)用方面。
它確??珙I(lǐng)域關(guān)注點(diǎn)在一個(gè)內(nèi)聚的代碼組件中定義。
AOP (Aspect-Oriented Programming)是一種通過允許 跨領(lǐng)域關(guān)注點(diǎn)分離來提高模塊化的編程模式。這些跨部門關(guān)注點(diǎn)與主要業(yè)務(wù)邏輯不同。我們可以在不修改代碼本身的情況下向現(xiàn)有代碼添加其他行為。
Spring的AOP框架可幫助我們實(shí)現(xiàn)這些跨領(lǐng)域的關(guān)注。
使用AOP,我們?cè)谝粋€(gè)地方。我們可以自由定義應(yīng)用此功能的方式和位置,而無需修改應(yīng)用新功能的類?,F(xiàn)在,可以將橫切關(guān)注點(diǎn)模塊化為特殊類,稱為 方面。
方面有 兩個(gè)的優(yōu)點(diǎn):
首先,每個(gè)關(guān)注點(diǎn)的邏輯現(xiàn)在都集中在一個(gè)地方,而不是分散在整個(gè)代碼庫中。 其次,業(yè)務(wù)模塊僅包含主要關(guān)注的代碼。次要關(guān)注點(diǎn)已移至方面。
各個(gè)方面都有要執(zhí)行的職責(zé),稱為 Advice。我們可以在一個(gè)或多個(gè)連接點(diǎn)將方面的功能實(shí)現(xiàn)到程序中。
它是用純Java實(shí)現(xiàn)的。 不需要特殊的編譯過程。 它僅支持方法執(zhí)行連接點(diǎn)。 僅提供運(yùn)行時(shí)編織。 有兩種類型的AOP代理: JDK動(dòng)態(tài)代理和 CGLIB代理。
跨領(lǐng)域關(guān)注點(diǎn)是我們要在應(yīng)用程序中的多個(gè)位置實(shí)現(xiàn)的關(guān)注點(diǎn)。它會(huì)影響整個(gè)應(yīng)用程序。
Aspect: 方面是一個(gè)模塊,其中封裝了advice和pointcuts,并提供cross-cutting可以有許多方面。我們可以使用帶有 @Aspect 批注的常規(guī)類來實(shí)現(xiàn)方面。 Pointcut: 切入點(diǎn)是一種表達(dá)式,它選擇一個(gè)或多個(gè)執(zhí)行Advice的連接點(diǎn)。我們可以使用expressions或patterns定義切入點(diǎn)。它使用與聯(lián)接點(diǎn)匹配的不同類型的表達(dá)式。在Spring Framework中,使用 AspectJ 切入點(diǎn)表達(dá)語言。 Join point: 連接點(diǎn)是應(yīng)用程序中應(yīng)用 AOP方面的點(diǎn)?;蛘咚茿dvice的特定執(zhí)行實(shí)例。在AOP中,連接點(diǎn)可以是方法執(zhí)行,異常處理,更改對(duì)象變量值等。 Advice: Advice是我們?cè)诜椒▓?zhí)行之前before或after采取的措施。該動(dòng)作是在程序執(zhí)行期間調(diào)用的一段代碼。SpringAOP框架中有五種類型的Advice: 在Advicebefore, after, after-returning, after-throwing和around advice。 是針對(duì)特定join point的Advice。 我們將在本節(jié)中進(jìn)一步討論這些Advice。 Target object: 一個(gè)應(yīng)用了Advice的對(duì)象稱為target object。目標(biāo)對(duì)象始終是proxied,這意味著在運(yùn)行時(shí)將創(chuàng)建一個(gè)覆蓋目標(biāo)方法的子類,并根據(jù)其配置包含Advice。 Weaving: 這是將各個(gè)方面與其他應(yīng)用程序類型進(jìn)行linking aspects的過程。我們可以在運(yùn)行時(shí),加載時(shí)間和編譯時(shí)進(jìn)行織造。
Proxy: 它是在將Advice應(yīng)用于目標(biāo)對(duì)象后創(chuàng)建的對(duì)象,稱為 proxy 。 Spring AOP實(shí)現(xiàn)了 JDK動(dòng)態(tài)代理,以使用目標(biāo)類和Advice調(diào)用創(chuàng)建代理類。這些稱為AOP代理類。
AOP與OOP之間的區(qū)別如下:
AOP | OOP |
Aspect: 一個(gè)封裝切入點(diǎn),Advice和屬性的代碼單元。 | Class: 一個(gè)封裝方法和屬性的代碼單元。 |
Pointcut: 它定義了執(zhí)行Advice的一組入口點(diǎn)。 | Method signature: 。它定義了執(zhí)行方法主體的入口點(diǎn)。 |
Advice: 這是跨領(lǐng)域關(guān)注點(diǎn)的實(shí)現(xiàn)。 | Method bodies: 是業(yè)務(wù)邏輯問題的實(shí)現(xiàn)。 |
Waver: 借助Advice構(gòu)造代碼(源或?qū)ο?。 | Compiler: 它將源代碼轉(zhuǎn)換為目標(biāo)代碼。 |
AOP和OOP之間的區(qū)別如下:
Spring AOP | AspectJ |
需要單獨(dú)的編譯過程。 | 它需要AspectJ編譯器。 |
它僅支持方法執(zhí)行切入點(diǎn)。 | 它支持所有切入點(diǎn)。 |
它可以在Spring Container管理的bean上實(shí)現(xiàn)。 | 它可以在所有域?qū)ο笊蠈?shí)現(xiàn)。 |
它僅支持方法級(jí)編織。 | 它可以波動(dòng)字段,方法,構(gòu)造函數(shù),靜態(tài)初始化器,最終類等。 |
AOP Advice有五種類型,如下所示:
Before Advice After Advice Around Advice After Throwing After Returning
Before Advice: 在連接點(diǎn)之前執(zhí)行的Advice在通知之前被調(diào)用。我們使用 @Before 批注將Advice標(biāo)記為Before通知。
After Advice: 在連接點(diǎn)之后執(zhí)行的Advice被稱為after notification。我們使用 @After 注解將Advice標(biāo)記為After通知。
Around Advice: 在連接點(diǎn)之前和之后執(zhí)行的Advice是
After Throwing: 在連接點(diǎn)拋出異常時(shí)執(zhí)行的Advice。
After Returning: 當(dāng)方法成功執(zhí)行時(shí)執(zhí)行的Advice。
在應(yīng)用程序中實(shí)現(xiàn)AOP之前,我們需要在pom.xml文件中添加 Spring AOP 依賴項(xiàng)。
Spring Boot Starter AOP是提供Spring AOP和AspectJ的依賴項(xiàng)。 AOP提供基本的AOP功能,而AspectJ提供完整的AOP框架。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>2.2.2.RELEASE</version> </dependency>
在下一節(jié)中,我們將在應(yīng)用程序中實(shí)現(xiàn)不同的Advice。