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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

【SSM框架系列】Spring 的 AOP(面向切面编程)

發(fā)布時間:2025/5/22 javascript 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【SSM框架系列】Spring 的 AOP(面向切面编程) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

什么是 AOP

  • AOP 為 Aspect Oriented Programming 的縮寫,意思為面向切面編程,是通過預編譯方式和運行期動態(tài)代理實現(xiàn)程序功能的統(tǒng)一維護的一種技術。
  • AOP 是 OOP (面向對象)的延續(xù),是軟件開發(fā)中的一個熱點,也是Spring框架中的一個重要內(nèi)容,是函數(shù)式編程的一種衍生范型。利用AOP可以對業(yè)務邏輯的各個部分進行隔離,從而使得業(yè)務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發(fā)的效率。
  • AOP 可以通過編譯方式和運行期動態(tài)代理實現(xiàn)在不修改源代碼的情況下,為程序統(tǒng)一添加/增強功能的一種技術
  • 如果說面向對象編程是關注將需求功能劃分為不同的并且相對獨立,封裝良好的類,并且讓它們有著屬于自己的行為,依靠繼承和多態(tài)等來定義彼此的關系的話,那么面向切面編程則是希望能夠將通用需求功能從不相關的類當中抽離出來,能夠使得很多類共享一個行為,一旦發(fā)生變化,不必修改很多類,而只需要修改這個行為即可
  • 面向對象編程思想好像一個父類的思想,面向切面編程思想更像一個接口思想

AOP 的作用及其優(yōu)勢

  • 作用:在程序運行期間,在不修改源碼的情況下對方法進行功能增強

  • 優(yōu)勢:減少重復代碼,提高開發(fā)效率,并且便于維護

  • 解耦合:將日志記錄,性能統(tǒng)計,事務處理,異常處理等代碼從業(yè)務邏輯代碼中劃分出來,通過對這些行為的分離,我們希望可以將它們獨立到非指導業(yè)務邏輯的方法中,進而改變這些行為的時候,不影響業(yè)務邏輯的代碼

  • AOP 是一個概念,并沒有設定具體語言的實現(xiàn),他能克服那些只有單繼承特性語言的缺點(如java)。可以簡單的把AOP理解成一種橫切增強操作,就像臨時查酒駕一樣,在程序里面的橫切行為大致如下:

    • 日志記錄,跟蹤,優(yōu)化和監(jiān)控
    • 性能的統(tǒng)計,優(yōu)化
    • 事務的處理
    • 持久化
    • 異常捕捉及處理
    • 資源池(如數(shù)據(jù)庫連接池)的管理
    • 系統(tǒng)統(tǒng)一的認證,權限管理等
    • 針對具體行業(yè)應用的橫切行為

AOP 的底層實現(xiàn)

實際上,AOP 的底層是通過 Spring 提供的的動態(tài)代理技術實現(xiàn)的。在運行期間,Spring通過動態(tài)代理技術動態(tài)的生成代理對象,代理對象方法執(zhí)行時進行增強功能的介入,在去調(diào)用目標對象的方法,從而完成功能的增強。
也就是業(yè)務代碼該怎么寫就怎么寫,在需要增強業(yè)務代碼的時候,可以通過AOP動態(tài)的將工具類代碼植入進去

AOP 的動態(tài)代理技術

常用的動態(tài)代理技術

JDK 代理 : 基于接口的動態(tài)代理技術

cglib 代理:基于父類的動態(tài)代理技術

JDK 的動態(tài)代理

實現(xiàn)邏輯:

  • 目標類必須是實現(xiàn)一個接口
  • 代理類是在內(nèi)存中創(chuàng)建的一個同樣實現(xiàn)上述接口的類(目標類和代理類是兄弟關系)
  • 因為實現(xiàn)相同接口,所以兩者方法個數(shù)及每個方法對應的聲明一致,在生成的代理類中做目標類方法的增強,代理類的方法會調(diào)用目標方法執(zhí)行原來具體的功能,同時會有自己的增強代碼,目標方法+代理的增強代碼共同構成了增強后的代理方法

①目標類接口

public interface TargetInterface {public void method(); }

②目標類

public class Target implements TargetInterface {public void method() {System.out.println("Target running....");} }

③動態(tài)代理代碼

public class JDKDynamicProxy {public static void main(String[] args) {// 1. 創(chuàng)建目標對象:目標對象類 目標對象 = new 目標對象類();final Target target = new Target();// 2. 創(chuàng)建代理對象// 該方法返回值即為動態(tài)代理對象,該代理對象將方法調(diào)用分派調(diào)用處理程序TargetInterface proxyTarget = (TargetInterface) Proxy.newProxyInstance(// 類加載器,第三類加載器,可以使用任意自定義的類獲取// 目標對象.getClass().getClassLoader()target.getClass().getClassLoader(), // 目標對象實現(xiàn)的所有接口,讓生成的代理對象,也實現(xiàn)相同接口,擁有和目標對象相同的方法// 目標對象.getClass().getInterfaces()target.getClass().getInterfaces(), // 代理對象調(diào)用方法的時候,都是通過這個來處理,最終由處理器的invoke方法執(zhí)行new InvocationHandler() {// proxy: 動態(tài)代理對象,我們一般不用,讓程序使用// method: 目標方法,目標對象的某個被增強的方法的包裝類對象// args: 目標方法的參數(shù)列表public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// 前置增強(在原方法運行前,添加代碼,以增強/修改方法體)System.out.println("前置增強代碼...");// 目標方法的返回值 = Method.invoke(目標對象, 目標方法的參數(shù)列表);Object invoke = method.invoke(target, args);// 后置增強(在原方法運行后,添加代碼,以增強/修改方法體)System.out.println("后置增強代碼...");// 這里可以增強(修改)原方法的返回值// return 被增強方法的返回值 或 null;return invoke;}});//3. 調(diào)用代理對象方法// 調(diào)用的是被代理對象的方法。我們并沒有編寫一個類(代理類),讓其實現(xiàn)TargetInterface接口。// 但是jdk動態(tài)代理會在程序運行時動態(tài)的生成一個代理類及其對象,并調(diào)用增強方法。// 增強方法會執(zhí)行增強代碼,同時也會調(diào)用被增強方法以實現(xiàn)原有功能// 動態(tài)代理對象.增強的方法(方法名與增強前相同)();proxyTarget.method();}}

④ 調(diào)用代理對象的方法測試

//3. 調(diào)用代理對象方法 proxyTarget.method();

cglib 的動態(tài)代理

實現(xiàn)邏輯:

  • “代理”的目的是構造一個和被代理的對象(目標對象)有同樣行為(行為相同,但行為能力已被增強)的對象,一個對象的行為是在類中定義的,對象只是類的實例,所有構造代理,不一定非得通過持有,包裝對象這一種方式
  • 與JDK動態(tài)代理中的代理類和目標類需要實現(xiàn)同一個接口不同,cglib動態(tài)代理中代理類不需要和目標類實現(xiàn)同一個接口,而是代理類繼承了目標類,通過“繼承”可以繼承父類所有的公開方法,然后可以重寫這些方法,在重寫時,對這些方法增強,這就是cglib的思想,當然這些增強都是程序運行時在內(nèi)存中進行的

①目標類

public class Target {public void method() {System.out.println("Target running....");} }

②動態(tài)代理代碼

Target target = new Target(); //創(chuàng)建目標對象 // 創(chuàng)建增強器 增強器類 增強器引用 = new 增強器類(); Enhancer enhancer = new Enhancer(); //創(chuàng)建增強器 // 使用增強器設置父類(父類就是目標類)enhancer.setSuperclass(Class clazz) // 增強器引用.設置父類(父類字節(jié)碼文件對象); enhancer.setSuperclass(Target.class); //設置父類 // 使用增強器設置回調(diào)(該方法無返回值)enhancer.setCallback(Callback callback) /* * 在回調(diào)是需要傳入一個Callback接口對象,通過創(chuàng)建實現(xiàn)了MethodInterceptor接口的匿名內(nèi)部類的對 * 象來實現(xiàn),創(chuàng)建對象時,需要明確方法的增強邏輯,增強邏輯的代碼需要寫在實現(xiàn)了MethodInterceptor * 接口的類的intercept()方法中,可以實現(xiàn)前置,后置,參數(shù)列表和返回值的增強 */ enhancer.setCallback(new MethodInterceptor() { //設置回調(diào)/*o 代理類對象,即thismethod 父類方法包裝對象objects 被增強方法的參數(shù)methodProxy 子類增強方法包裝對象*/@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("前置代碼增強....");// 這里建議使用methodProxy.invokeSuper(proxy, args)// 不要使用method對象,避免出現(xiàn)遞歸調(diào)用造成內(nèi)存溢出Object invoke = method.invoke(target, objects);System.out.println("后置代碼增強....");return invoke;} }); // 使用增強器創(chuàng)建對象,返回的就是代理類對象(子類對象)enhancer.creat() Target proxy = (Target) enhancer.create(); //創(chuàng)建代理對象

③調(diào)用代理對象的方法測試

//測試,當調(diào)用接口的任何方法時,代理對象的代碼都無序修改 proxy.method();

AOP 相關概念

  • Spring的 AOP 實現(xiàn)底層就是對上面的動態(tài)代理的代碼進行封裝,封裝后我們只需要對需要關注的部分進行代碼編寫,并通過配置的方式完成指定目標的方法增強
  • AOP 相關的術語,常用的術語如下:
    • Target(目標對象):代理的目標對象,目標類,被代理(被增強)的類
    • Proxy (代理):一個類被 AOP 織入增強后,就產(chǎn)生一個結果代理類,代理(增強)之后的類
    • Joinpoint(連接點):所謂連接點是指那些被攔截到的點。在spring中,這些點指的是方法,因為spring只支持方法類型的連接點,可以被攔截的方法(有很多)
    • Pointcut(切入點):所謂切入點是指我們要對哪些 Joinpoint 進行攔截的定義,(目標方法,攔截到并被增強的方法叫切點)
    • Advice(通知/ 增強):所謂通知是指攔截到 Joinpoint 之后所要做的事情就是通知,(增強方法,攔截到方法之后,所要做的具體的增強內(nèi)容)
    • Aspect(切面):是切入點和通知(引介)的結合(目標方法 + 增強方法)
    • Weaving(織入):是指把增強應用到目標對象來創(chuàng)建新的代理對象的過程。spring采用動態(tài)代理織入,而AspectJ采用編譯期織入和類裝載期織入,(是一個過程,目標方法 + 增強方法結合在一起的動作叫做織入)
  • 補充:將增強應用到切點的過程叫做織入,Spring采用動態(tài)代理織入,Aspectj使用編輯器織入和類裝載器織入
    • Aspectj是一個基于java語言的AOP框架,Spring2.0開始,Spring AOP引入對Aspectj擴展了java語言,提供了一個專門的編譯器,在編譯時提供橫向代碼的織入
    • 早期Spring AOP開發(fā)使用的是自己的AOP技術,目前階段 Spring AOP開發(fā)通常使用Aspectj技術來實現(xiàn)

AOP 開發(fā)明確的事項

  • 需要編寫的內(nèi)容
    • 編寫核心業(yè)務代碼(目標類的目標方法)
    • 編寫切面類,切面類中有通知(增強功能方法,增強方法需要寫在切面類內(nèi)部)
    • 在配置文件中,配置織入關系,即將哪些通知與哪些連接點進行結合
  • AOP 技術實現(xiàn)的內(nèi)容
    • Spring 框架監(jiān)控切入點方法的執(zhí)行,一旦監(jiān)控到切入點方法被運行,使用代理機制,動態(tài)創(chuàng)建目標對象的代理對象,根據(jù)通知類別,在代理對象的對應位置,將通知對應的功能織入,完成完整的代碼邏輯運行
    • Spring 框架監(jiān)控切點方法的執(zhí)行,通過配置指定哪些方法是切點,一旦監(jiān)控到切點方法被執(zhí)行,就使用動態(tài)代理創(chuàng)建(切點所屬類的)目標對象的代理對象,然后根據(jù)通知(增強)類別(前置增強,后置增強),在代理對象的對應位置,將通知(增強)的內(nèi)容織入,完成完整的代碼邏輯運行
  • AOP 底層使用哪種代理方式
    • 在Spring中,框架會根據(jù)目標類是否實現(xiàn)了接口來決定采用哪種動態(tài)代理的方式
      • 有父接口:選擇JDK動態(tài)代理
      • 無父接口:選擇cglib動態(tài)代理
  • 基于 XML 的 AOP 開發(fā)

    ①導入 AOP 相關坐標

    <!--導入spring的context坐標,context依賴aop--> <dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.5.RELEASE</version> </dependency> <!-- aspectj的織入 --> <dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.13</version> </dependency>

    ②創(chuàng)建目標接口和目標類(內(nèi)部有切點)

    public interface TargetInterface {public void method(); }public class Target implements TargetInterface {@Overridepublic void method() {System.out.println("Target running....");} }

    ③創(chuàng)建切面類(內(nèi)部有增強方法)

    public class MyAspect {//前置增強方法public void before(){System.out.println("前置代碼增強.....");} }

    ④將目標類和切面類的對象創(chuàng)建權交給 spring

    <!--配置目標類--> <bean id="target" class="cs.wy.aop.Target"></bean> <!--配置切面類--> <bean id="myAspect" class="cs.wy.aop.MyAspect"></bean>

    ⑤在 applicationContext.xml 中配置織入關系,配置切點表達式和前置增強的織入關系

    <aop:config><!--引用myAspect的Bean為切面對象--><aop:aspect ref="myAspect"><!--配置Target的method方法執(zhí)行時要進行myAspect的before方法前置增強--><aop:before method="before" pointcut="execution(public void cs.wy.aop.Target.method())"></aop:before></aop:aspect> </aop:config>

    XML 配置 AOP 詳解

    1) 切點表達式的寫法

    表達式語法:

    execution([修飾符] 返回值類型 包名.類名.方法名(參數(shù)))
    • 訪問修飾符可以省略

    • 返回值類型、包名、類名、方法名可以使用星號* 代表任意

    • 包名與類名之間一個點 . 代表當前包下的類,兩個點 … 表示當前包及其子包下的類

    • 參數(shù)列表可以使用兩個點 … 表示任意個數(shù),任意類型的參數(shù)列表

    例如:

    <!-- aop包下Target類下無參數(shù)的method方法--> execution(public void cs.wy.aop.Target.method()) execution(void cs.wy.aop.Target.*(..)) execution(* cs.wy.aop.*.*(..)) execution(* cs.wy.aop..*.*(..)) execution(* *..*.*(..))
    2) 通知的類型

    通知的配置語法:

    <aop:通知類型 method=“切面類中方法名” pointcut=“切點表達式"></aop:通知類型>

    3) 切點表達式的抽取

    當多個增強的切點表達式相同時,可以將切點表達式進行抽取,在增強中使用 pointcut-ref 屬性代替 pointcut 屬性來引用抽取后的切點表達式。

    <aop:config><!--引用myAspect的Bean為切面對象--><aop:aspect ref="myAspect"><aop:pointcut id="myPointcut" expression="execution(* cs.wy.aop.*.*(..))"/><aop:before method="before" pointcut-ref="myPointcut"></aop:before></aop:aspect> </aop:config>

    基于注解的 AOP 開發(fā)

    ①創(chuàng)建目標接口和目標類(內(nèi)部有切點)

    public interface TargetInterface {public void method(); }public class Target implements TargetInterface {@Overridepublic void method() {System.out.println("Target running....");} }

    ②創(chuàng)建切面類(內(nèi)部有增強方法)

    public class MyAspect {//前置增強方法public void before(){System.out.println("前置代碼增強.....");} }

    ③將目標類和切面類的對象創(chuàng)建權交給 spring

    @Component("target") public class Target implements TargetInterface {@Overridepublic void method() {System.out.println("Target running....");} } @Component("myAspect") public class MyAspect {public void before(){System.out.println("前置代碼增強.....");} }

    ④在切面類中使用注解配置織入關系

    @Component("myAspect") @Aspect public class MyAspect {@Before("execution(* com.itheima.aop.*.*(..))")public void before(){System.out.println("前置代碼增強.....");} }

    ⑤在配置文件中開啟組件掃描和 AOP 的自動代理

    <!--組件掃描--> <context:component-scan base-package="cs.wy.aop"/><!--aop的自動代理--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    注解配置 AOP 詳解

    1) 注解通知的類型

    通知的配置語法:@通知注解(“切點表達式")

    2) 切點表達式的抽取

    同 xml配置
    aop 一樣,我們可以將切點表達式抽取。抽取方式是在切面內(nèi)定義方法,在該方法上使用@Pointcut注解定義切點表達式,然后在在增強注解中進行引用。具體如下:

    @@Component("myAspect") @Aspect public class MyAspect {@Before("MyAspect.myPoint()")public void before(){System.out.println("前置代碼增強.....");}@Pointcut("execution(* com.itheima.aop.*.*(..))")public void myPoint(){} }

    總結

    以上是生活随笔為你收集整理的【SSM框架系列】Spring 的 AOP(面向切面编程)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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