日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

Spring(4)——面向切面编程(AOP模块)

發(fā)布時(shí)間:2025/3/21 javascript 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring(4)——面向切面编程(AOP模块) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Spring AOP 簡(jiǎn)介

如果說(shuō) IoC 是 Spring 的核心,那么面向切面編程就是 Spring 最為重要的功能之一了,在數(shù)據(jù)庫(kù)事務(wù)中切面編程被廣泛使用。

AOP 即 Aspect Oriented Program 面向切面編程

首先,在面向切面編程的思想里面,把功能分為核心業(yè)務(wù)功能,和周邊功能。

  • 所謂的核心業(yè)務(wù),比如登陸,增加數(shù)據(jù),刪除數(shù)據(jù)都叫核心業(yè)務(wù)
  • 所謂的周邊功能,比如性能統(tǒng)計(jì),日志,事務(wù)管理等等

周邊功能在 Spring 的面向切面編程AOP思想里,即被定義為切面

在面向切面編程AOP的思想里面,核心業(yè)務(wù)功能和切面功能分別獨(dú)立進(jìn)行開(kāi)發(fā),然后把切面功能和核心業(yè)務(wù)功能 "編織" 在一起,這就叫AOP

AOP 的目的

AOP能夠?qū)⒛切┡c業(yè)務(wù)無(wú)關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任(例如事務(wù)處理、日志管理、權(quán)限控制等)封裝起來(lái),便于減少系統(tǒng)的重復(fù)代碼降低模塊間的耦合度,并有利于未來(lái)的可拓展性和可維護(hù)性

AOP 當(dāng)中的概念:

  • 切入點(diǎn)(Pointcut)
    在哪些類,哪些方法上切入(where
  • 通知(Advice)
    在方法執(zhí)行的什么實(shí)際(when:方法前/方法后/方法前后)做什么(what:增強(qiáng)的功能)
  • 切面(Aspect)
    切面 = 切入點(diǎn) + 通知,通俗點(diǎn)就是:在什么時(shí)機(jī),什么地方,做什么增強(qiáng)!
  • 織入(Weaving)
    把切面加入到對(duì)象,并創(chuàng)建出代理對(duì)象的過(guò)程。(由 Spring 來(lái)完成)

一個(gè)例子

為了更好的說(shuō)明 AOP 的概念,我們來(lái)舉一個(gè)實(shí)際中的例子來(lái)說(shuō)明:

在上面的例子中,包租婆的核心業(yè)務(wù)就是簽合同,收房租,那么這就夠了,灰色框起來(lái)的部分都是重復(fù)且邊緣的事,交給中介商就好了,這就是?AOP 的一個(gè)思想:讓關(guān)注點(diǎn)代碼與業(yè)務(wù)代碼分離!

實(shí)際的代碼

我們來(lái)實(shí)際的用代碼感受一下

1.在 Package【pojo】下新建一個(gè)【Landlord】類(我百度翻譯的包租婆的英文):

package pojo;import org.springframework.stereotype.Component;@Component("landlord") public class Landlord {public void service() {// 僅僅只是實(shí)現(xiàn)了核心的業(yè)務(wù)功能System.out.println("簽合同");System.out.println("收房租");} }

2.在 Package【aspect】下新建一個(gè)中介商【Broker】類(我還是用的翻譯...):

package aspect;import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component;@Component @Aspect class Broker {@Before("execution(* pojo.Landlord.service())")public void before(){System.out.println("帶租客看房");System.out.println("談價(jià)格");}@After("execution(* pojo.Landlord.service())")public void after(){System.out.println("交鑰匙");} }

3.在 applicationContext.xml 中配置自動(dòng)注入,并告訴 Spring IoC 容器去哪里掃描這兩個(gè) Bean:

<?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:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><context:component-scan base-package="aspect" /><context:component-scan base-package="pojo" /><aop:aspectj-autoproxy/> </beans>

4.在 Package【test】下編寫(xiě)測(cè)試代碼:

package test;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import pojo.Landlord;public class TestSpring {public static void main(String[] args) {ApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");Landlord landlord = (Landlord) context.getBean("landlord", Landlord.class);landlord.service();} }

5.執(zhí)行看到效果:

這個(gè)例子使用了一些注解,現(xiàn)在看不懂沒(méi)有關(guān)系,但我們可以從上面可以看到,我們?cè)?Landlord 的 service() 方法中僅僅實(shí)現(xiàn)了核心的業(yè)務(wù)代碼,其余的關(guān)注點(diǎn)功能是根據(jù)我們?cè)O(shè)置的切面自動(dòng)補(bǔ)全的。


使用注解來(lái)開(kāi)發(fā) Spring AOP

使用注解的方式已經(jīng)逐漸成為了主流,所以我們利用上面的例子來(lái)說(shuō)明如何用注解來(lái)開(kāi)發(fā) Spring AOP

第一步:選擇連接點(diǎn)

Spring 是方法級(jí)別的 AOP 框架,我們主要也是以某個(gè)類額某個(gè)方法作為連接點(diǎn),另一種說(shuō)法就是:選擇哪一個(gè)類的哪一方法用以增強(qiáng)功能。

....public void service() {// 僅僅只是實(shí)現(xiàn)了核心的業(yè)務(wù)功能System.out.println("簽合同");System.out.println("收房租");}....

我們?cè)谶@里就選擇上述 Landlord 類中的 service() 方法作為連接點(diǎn)。

第二步:創(chuàng)建切面

選擇好了連接點(diǎn)就可以創(chuàng)建切面了,我們可以把切面理解為一個(gè)攔截器,當(dāng)程序運(yùn)行到連接點(diǎn)的時(shí)候,被攔截下來(lái),在開(kāi)頭加入了初始化的方法,在結(jié)尾也加入了銷毀的方法而已,在 Spring 中只要使用?@Aspect?注解一個(gè)類,那么 Spring IoC 容器就會(huì)認(rèn)為這是一個(gè)切面了:

package aspect;import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component;@Component @Aspect class Broker {@Before("execution(* pojo.Landlord.service())")public void before(){System.out.println("帶租客看房");System.out.println("談價(jià)格");}@After("execution(* pojo.Landlord.service())")public void after(){System.out.println("交鑰匙");} }
  • 注意:?被定義為切面的類仍然是一個(gè) Bean ,需要?@Component?注解標(biāo)注

代碼部分中在方法上面的注解看名字也能猜出個(gè)大概,下面來(lái)列舉一下 Spring 中的 AspectJ 注解:

注解說(shuō)明
@Before前置通知,在連接點(diǎn)方法前調(diào)用
@Around環(huán)繞通知,它將覆蓋原有方法,但是允許你通過(guò)反射調(diào)用原有方法,后面會(huì)講
@After后置通知,在連接點(diǎn)方法后調(diào)用
@AfterReturning返回通知,在連接點(diǎn)方法執(zhí)行并正常返回后調(diào)用,要求連接點(diǎn)方法在執(zhí)行過(guò)程中沒(méi)有發(fā)生異常
@AfterThrowing異常通知,當(dāng)連接點(diǎn)方法異常時(shí)調(diào)用

有了上表,我們就知道 before() 方法是連接點(diǎn)方法調(diào)用前調(diào)用的方法,而 after() 方法則相反,這些注解中間使用了定義切點(diǎn)的正則式,也就是告訴 Spring AOP 需要攔截什么對(duì)象的什么方法,下面講到。

第三步:定義切點(diǎn)

在上面的注解中定義了 execution 的正則表達(dá)式,Spring 通過(guò)這個(gè)正則表達(dá)式判斷具體要攔截的是哪一個(gè)類的哪一個(gè)方法:

execution(* pojo.Landlord.service())

依次對(duì)這個(gè)表達(dá)式作出分析:

  • execution:代表執(zhí)行方法的時(shí)候會(huì)觸發(fā)
  • *?:代表任意返回類型的方法
  • pojo.Landlord:代表類的全限定名
  • service():被攔截的方法名稱

通過(guò)上面的表達(dá)式,Spring 就會(huì)知道應(yīng)該攔截 pojo.Lnadlord 類下的 service() 方法。上面的演示類還好,如果多出都需要寫(xiě)這樣的表達(dá)式難免會(huì)有些復(fù)雜,我們可以通過(guò)使用?@Pointcut?注解來(lái)定義一個(gè)切點(diǎn)來(lái)避免這樣的麻煩:

package aspect;import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component;@Component @Aspect class Broker {@Pointcut("execution(* pojo.Landlord.service())")public void lService() {}@Before("lService()")public void before() {System.out.println("帶租客看房");System.out.println("談價(jià)格");}@After("lService()")public void after() {System.out.println("交鑰匙");} }

第四步:測(cè)試 AOP

編寫(xiě)測(cè)試代碼,但是我這里因?yàn)?JDK 版本不兼容出現(xiàn)了 BUG....(尷尬...)

這就告訴我們:環(huán)境配置很重要...不然莫名其妙的 BUG 讓你崩潰...

環(huán)繞通知

我們來(lái)探討一下環(huán)繞通知,這是 Spring AOP 中最強(qiáng)大的通知,因?yàn)樗闪饲爸猛ㄖ秃笾猛ㄖ?#xff0c;它保留了連接點(diǎn)原有的方法的功能,所以它及強(qiáng)大又靈活,讓我們來(lái)看看:

package aspect;import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component;@Component @Aspect class Broker {// 注釋掉之前的 @Before 和 @After 注解以及對(duì)應(yīng)的方法 // @Before("execution(* pojo.Landlord.service())") // public void before() { // System.out.println("帶租客看房"); // System.out.println("談價(jià)格"); // } // // @After("execution(* pojo.Landlord.service())") // public void after() { // System.out.println("交鑰匙"); // }// 使用 @Around 注解來(lái)同時(shí)完成前置和后置通知@Around("execution(* pojo.Landlord.service())")public void around(ProceedingJoinPoint joinPoint) {System.out.println("帶租客看房");System.out.println("談價(jià)格");try {joinPoint.proceed();} catch (Throwable throwable) {throwable.printStackTrace();}System.out.println("交鑰匙");} }

運(yùn)行測(cè)試代碼,結(jié)果仍然正確:


使用 XML 配置開(kāi)發(fā) Spring AOP

注解是很強(qiáng)大的東西,但基于 XML 的開(kāi)發(fā)我們?nèi)匀恍枰私?#xff0c;我們先來(lái)了解一下 AOP 中可以配置的元素:

AOP 配置元素用途備注
aop:advisor定義 AOP 的通知其一種很古老的方式,很少使用
aop:aspect定義一個(gè)切面——
aop:before定義前置通知——
aop:after定義后置通知——
aop:around定義環(huán)繞通知——
aop:after-returning定義返回通知——
aop:after-throwing定義異常通知——
aop:config頂層的 AOP 配置元素AOP 的配置是以它為開(kāi)始的
aop:declare-parents給通知引入新的額外接口,增強(qiáng)功能——
aop:pointcut定義切點(diǎn)——

有了之前通過(guò)注解來(lái)編寫(xiě)的經(jīng)驗(yàn),并且有了上面的表,我們將上面的例子改寫(xiě)成 XML 配置很容易(去掉所有的注解):

<!-- 裝配 Bean--> <bean name="landlord" class="pojo.Landlord"/> <bean id="broker" class="aspect.Broker"/><!-- 配置AOP --> <aop:config><!-- where:在哪些地方(包.類.方法)做增加 --><aop:pointcut id="landlordPoint"expression="execution(* pojo.Landlord.service())"/><!-- what:做什么增強(qiáng) --><aop:aspect id="logAspect" ref="broker"><!-- when:在什么時(shí)機(jī)(方法前/后/前后) --><aop:around pointcut-ref="landlordPoint" method="around"/></aop:aspect> </aop:config>

運(yùn)行測(cè)試程序,看到正確結(jié)果:

擴(kuò)展閱讀:Spring【AOP模塊】就這么簡(jiǎn)單?、?關(guān)于 Spring AOP(AspectJ)你該知曉的一切(慎獨(dú)讀,有些深度...)

參考資料:

  • 《Java EE 互聯(lián)網(wǎng)輕量級(jí)框架整合開(kāi)發(fā)》
  • 《Java 實(shí)戰(zhàn)(第四版)》
  • 萬(wàn)能的百度 and 萬(wàn)能的大腦

歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處!
簡(jiǎn)書(shū)ID:@我沒(méi)有三顆心臟

總結(jié)

以上是生活随笔為你收集整理的Spring(4)——面向切面编程(AOP模块)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。