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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

AspectJ 使用介绍

發布時間:2023/12/20 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 AspectJ 使用介绍 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • AspectJ 使用介紹
    • Compile-Time Weaving
    • Post-Compile Weaving
    • Load-Time Weaving
    • 小結

上一篇文章,我們介紹了 Spring AOP 的各種用法,包括隨著 Spring 的演進而發展出來的幾種配置方式。

但是我們始終沒有使用到 AspectJ,即使是在基于注解的 @AspectJ 的配置方式中,Spring 也僅僅是使用了 AspectJ 包中的一些注解而已,并沒有依賴于 AspectJ 實現具體的功能。

本文將介紹使用 AspectJ,介紹它的 3 種織入方式。

本文使用的測試源碼已上傳到 Github: hongjiev/aspectj-learning,如果你在使用過程中碰到麻煩,請在評論區留言。

目錄:

AspectJ 使用介紹

AspectJ 作為 AOP 編程的完全解決方案,提供了三種織入時機,分別為

  • compile-time:編譯期織入,在編譯的時候一步到位,直接編譯出包含織入代碼的 .class 文件
  • post-compile:編譯后織入,增強已經編譯出來的類,如我們要增強依賴的 jar 包中的某個類的某個方法
  • load-time:在 JVM 進行類加載的時候進行織入
  • 本節中的內容參考了《Intro to AspectJ》,Baeldung 真的是挺不錯的一個 Java 博客。

    首先,先把下面兩個依賴加進來:

    <dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.13</version> </dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.13</version> </dependency>

    我們后面需要用到下面這個類,假設賬戶初始有 20 塊錢,之后會調 account.pay(amount) 進行付款:

    public class Account {int balance = 20;public boolean pay(int amount) {if (balance < amount) {return false;}balance -= amount;return true;} }

    下面,我們定義兩個 Aspect 來進行演示:

    • AccountAspect:用 AspectJ 的語法來寫,對交易進行攔截,如此次交易超過余額,直接拒絕。
    • ProfilingAspect:用 Java 來寫,用于記錄方法的執行時間

    AccountAspect 需要以 .aj 結尾,如我們在 com.javadoop.aspectjlearning.aspectj 的 package 下新建文件 AccountAspect.aj,內容如下:

    package com.javadoop.aspectjlearning.aspect;import com.javadoop.aspectjlearning.model.Account;public aspect AccountAspect {pointcut callPay(int amount, Account account):call(boolean com.javadoop.aspectjlearning.model.Account.pay(int)) && args(amount) && target(account);before(int amount, Account account): callPay(amount, account) {System.out.println("[AccountAspect]付款前總金額: " + account.balance);System.out.println("[AccountAspect]需要付款: " + amount);}boolean around(int amount, Account account): callPay(amount, account) {if (account.balance < amount) {System.out.println("[AccountAspect]拒絕付款!");return false;}return proceed(amount, account);}after(int amount, Account balance): callPay(amount, balance) {System.out.println("[AccountAspect]付款后,剩余:" + balance.balance);}}

    上面 .aj 的語法我們可能不熟悉,但是看上去還是簡單的,分別處理了 before、around 和 after 的場景。

    我們再來看用 Java 寫的 ProfilingAspect.java:

    package com.javadoop.aspectjlearning.aspect;import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut;@Aspect public class ProfilingAspect {@Pointcut("execution(* com.javadoop.aspectjlearning.model.*.*(..))")public void modelLayer() {}@Around("modelLayer()")public Object logProfile(ProceedingJoinPoint joinPoint) throws Throwable {long start = System.currentTimeMillis();Object result = joinPoint.proceed();System.out.println("[ProfilingAspect]方法: 【" + joinPoint.getSignature() + "】結束,用時: " + (System.currentTimeMillis() - start));return result;} }

    接下來,我們討論怎么樣將定義好的兩個 Aspects 織入到我們的 Account 的付款方法 pay(amount) 中,也就是三種織入時機分別是怎么實現的。

    Compile-Time Weaving

    這是最簡單的使用方式,在編譯期的時候進行織入,這樣編譯出來的 .class 文件已經織入了我們的代碼,在 JVM 運行的時候其實就是加載了一個普通的被織入了代碼的類。

    如果你是采用 maven 進行管理,可以在 <build> 中加入以下的插件:

    <!-- 編譯期織入 --> <plugin><groupId>org.codehaus.mojo</groupId><artifactId>aspectj-maven-plugin</artifactId><version>1.7</version><configuration><complianceLevel>1.8</complianceLevel><source>1.8</source><target>1.8</target><showWeaveInfo>true</showWeaveInfo><verbose>true</verbose><Xlint>ignore</Xlint><encoding>UTF-8</encoding></configuration><executions><execution><goals><goal>compile</goal><goal>test-compile</goal></goals></execution></executions> </plugin>

    AccountAspect.aj 文件 javac 是沒法編譯的,所以上面這個插件其實充當了編譯的功能。

    然后,我們就可以運行了:

    public class Application {public static void main(String[] args) {testCompileTime();}public static void testCompileTime() {Account account = new Account();System.out.println("==================");account.pay(10);account.pay(50);System.out.println("==================");} }

    輸出:

    ================== [AccountAspect]付款前總金額: 20 [AccountAspect]需要付款: 10 [ProfilingAspect]方法: 【boolean com.javadoop.aspectjlearning.model.Account.pay(int)】結束,用時: 1 [AccountAspect]付款后,剩余:10 [AccountAspect]付款前總金額: 10 [AccountAspect]需要付款: 50 [AccountAspect]拒絕付款! [AccountAspect]付款后,剩余:10 ==================

    結果看上去就很神奇(我們知道是 aop 搞的鬼當然會覺得不神奇),其實奧秘就在于 main 函數中的代碼被改變了,不再是上面幾行簡單的代碼了,而是進行了織入:

    我們的 Account 類也不再像原來定義的那樣了:

    編譯期織入理解起來應該還是比較簡單,就是在編譯的時候先修改了代碼再進行編譯。

    Post-Compile Weaving

    Post-Compile Weaving 和 Compile-Time Weaving 非常類似,我們也是直接用場景來說。

    我們假設上面的 Account 類在 aspectj-learning-share.jar 包中,我們的工程 aspectj-learning 依賴了這個 jar 包。

    由于 Account 這個類已經被編譯出來了,我們要對它的方法進行織入,就需要用到編譯后織入。

    為了方便大家測試,盡量讓前面的用例也能跑起來。我們定義一個新的類 User,代碼和 Account 一樣,但是在 aspectj-learning-share.jar 包中,這個包就這一個類。

    同時也復制 AccountAspect 一份出來,命名為 UserAspect,稍微修改修改就可以用來處理 User 類了。

    首先,我們注釋掉之前編譯期織入使用的插件配置,增加以下插件配置(其實還是同一個插件):

    <!--編譯后織入--> <plugin><groupId>org.codehaus.mojo</groupId><artifactId>aspectj-maven-plugin</artifactId><version>1.11</version><configuration><complianceLevel>1.8</complianceLevel><weaveDependencies><weaveDependency><groupId>com.javadoop</groupId><artifactId>aspectj-learning-share</artifactId></weaveDependency></weaveDependencies></configuration><executions><execution><goals><goal>compile</goal></goals></execution></executions> </plugin>

    注意配置中的 <weaveDependency>,我們在 <dependencies> 中要配置好依賴,然后在這里進行配置。這樣就可以對其進行織入了。

    接下來,大家可以手動用 mvn clean package 編譯一下,然后就會看到以下結果:

    從上圖我們可以看到,上面的配置會把相應的 jar 包中的類加到當前工程的編譯結果中(User 類原本是在 aspectj-learning-share.jar 中的)。

    運行一下:

    java -jar target/aspectj-learning-1.0-jar-with-dependencies.jar

    運行結果也會如預期的一樣,UserAspect 對 User 進行了織入,這里就不贅述了。感興趣的讀者自己去跑一下,注意一定要用 mvn 命令,不要用 IDE,不然很多時候發現不了問題。

    Intellij 在 build 的時候會自己處理 AspectJ,而不是用我們配置的 maven 插件。

    Load-Time Weaving

    最后,我們要介紹的是 LTW 織入,正如 Load-Time 的名字所示,它是在 JVM 加載類的時候做的織入。AspectJ 允許我們在啟動的時候指定 agent 來實現這個功能。

    首先,我們先注釋掉之前在 pom.xml 中用于編譯期和編譯后織入使用的插件,免得影響我們的測試。

    我們要知道,一旦我們去掉了 aspectj 的編譯插件,那么 .aj 的文件是不會被編譯的。

    然后,我們需要在 JVM 的啟動參數中加上以下 agent(或在 IDE 中配置 VM options),如:

    -javaagent:/Users/hongjie/.m2/repository/org/aspectj/aspectjweaver/1.8.13/aspectjweaver-1.8.13.jar

    之后,我們需要在 resources 中配置 aop.xml 文件,放置在 META-INF 目錄中(resource/META-INF/aop.xml):

    <!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd"><aspectj> <aspects> <aspect name="com.javadoop.aspectjlearning.aspect.ProfilingAspect"/> <weaver options="-verbose -showWeaveInfo"> <include within="com.javadoop.aspectjlearning..*"/> </weaver> </aspects></aspectj>

    aop.xml 文件中的配置非常容易理解,只需要配置 Aspects 和需要被織入的類即可。

    我們用以下程序進行測試:

    public class Application { public static void main(String[] args) { testLoadTime(); } public static void testLoadTime() { Account account = new Account(); System.out.println("=================="); account.pay(10); account.pay(50); System.out.println("=================="); }}

    萬事具備了,我們可以開始跑起來了。

    第一步,編譯

    mvn clean package

    第二步,檢查編譯結果

    我們通過 IDE 查看編譯出來的代碼(IDE反編譯),可以看到,Application 類并未進行織入,Account 類也并未進行織入。

    第三步,運行

    從第二步我們可以看到,在運行之前,AspectJ 沒有做任何的事情。

    那么可以肯定的就是,AspectJ 會在運行期利用 aop.xml 中的配置進行織入處理。

    在命令行中執行以下語句:

    java -jar target/aspectj-learning-1.0-jar-with-dependencies.jar

    輸出為:

    ====================================

    可以看到沒有任何織入處理,然后執行以下語句再試試:

    java -javaagent:/Users/hongjie/.m2/repository/org/aspectj/aspectjweaver/1.8.13/aspectjweaver-1.8.13.jar -jar target/aspectj-learning-1.0-jar-with-dependencies.jar

    啟動的時候指定了 -javaagent:/.../aspectjweaver-1.8.13.jar,然后再看輸出結果:

    ==================[ProfilingAspect]方法: 【boolean com.javadoop.aspectjlearning.model.Account.pay(int)】結束,用時: 1[ProfilingAspect]方法: 【boolean com.javadoop.aspectjlearning.model.Account.pay(int)】結束,用時: 0==================

    我們可以看到 ProfilingAspect 已經進行了織入處理,這就是 Load-time Weaving。

    到這里,就要結束這一小節了,這里順便再介紹下如果用 maven 跑測試的話怎么搞。

    首先,我們往 surefire 插件中加上 javaagent:

    <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.10</version> <configuration> <argLine> -javaagent:/xxx/aspectjweaver-1.8.13.jar </argLine> <useSystemClassLoader>true</useSystemClassLoader> <forkMode>always</forkMode> </configuration></plugin>

    然后,我們就可以用 mvn test 看到織入效果了。還是那句話,不要用 IDE 進行測試,因為 IDE 太“智能”了。

    小結

    AspectJ 的三種織入方式中,個人覺得前面的兩種會比較實用一些,因為第三種需要修改啟動腳本,對于大型公司來說會比較不友好,需要專門找運維人員配置。

    在實際生產中,我們用得最多的還是純 Spring AOP,通過本文的介紹,相信大家對于 AspectJ 的使用應該也沒什么壓力了。

    大家如果對于本文介紹的內容有什么不清楚的,請直接在評論區留言,如果對于 Spring + AspectJ 感興趣的讀者,碰到問題也可以在評論區和大家互動討論。

    (全文完)

    總結

    以上是生活随笔為你收集整理的AspectJ 使用介绍的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 国产午夜精品久久久久久久 | 色av一区二区三区 | 免费的av网址 | 91免费精品视频 | 探花视频在线版播放免费观看 | 久久三级网站 | 大地资源二中文在线影视观看 | 日本一区二区高清视频 | 麻豆短视频 | 久久久久无码国产精品一区李宗瑞 | 精品色图| 一区二区三区精彩视频 | 成人午夜sm精品久久久久久久 | 国产精品2020| 亚洲成年网站 | 成人啪啪18免费游戏链接 | 香蕉视频污在线观看 | 日韩免费看片 | 国产精品.www | 久草视频2| 久久国产免费视频 | 欧美爽爽爽| 啪啪网站大全 | 免费观看久久 | 色老板精品凹凸在线视频观看 | 亚洲自拍偷拍网 | 亚洲午夜一区二区 | 亚洲综合99 | 精品96久久久久久中文字幕无 | 国产精品免费入口 | 日韩一区二区不卡 | 亚洲精品一区二区三区不卡 | 人与动物2免费观看完整版电影高清 | 蜜桃9999| 久久精品日韩 | 制服丝袜天堂 | 久久国产精品国语对白 | 久久久久激情 | 美女扒开腿让人桶爽 | 法国经典free性复古xxxx | 假日游船| 姐姐你真棒插曲快来救救我电影 | 在线三级av | 亚洲综合激情另类小说区 | 久久爱一区 | 亚洲精品一区二区三区四区 | 欧美日韩三 | 日韩在线观看av | 亚洲av乱码一区二区 | 精品人妻一区二区三区久久嗨 | 欧美日韩国产成人精品 | 国产成人综合欧美精品久久 | 97在线视频免费观看 | 51精品国产| 亚洲精品福利在线观看 | 一区二区午夜 | 亚洲国产成人综合 | 亚洲影视一区二区三区 | 欧美福利一区二区三区 | 一本久久综合亚洲鲁鲁五月天 | 香蕉视频在线观看视频 | 美女啪啪网址 | 久久艹在线视频 | 一区av在线 | 免费看a的网站 | 天堂视频一区二区 | 中文字幕在线免费观看 | 欧美日韩亚洲免费 | 色爽爽爽 | 秋霞电影一区二区 | 午夜影院h | 在线电影一区二区 | 国产午夜精品无码一区二区 | 你懂的在线视频网站 | 黄色特级一级片 | 91色视频在线观看 | 国产精品三级在线观看 | 中国黄色a级片 | 日本天堂在线观看 | 日韩欧美在线观看一区二区三区 | 国产精品国产三级国产传播 | 国产免费av电影 | 国产永久免费无遮挡 | 中文字幕精品在线 | 深夜激情网站 | 国产xxxx视频 | 香蕉久久夜色精品升级完成 | 疯狂揉花蒂控制高潮h | 人民的名义第二部 | 日韩欧美一区二 | 国产成人无码精品久久二区三 | 第一色网站| 日韩影音| 美国av一区二区 | 国产精九九网站漫画 | 国产精品高潮呻吟久久av野狼 | 国产精久久久久久 | 免费在线观看日韩 | 国产精品电影在线观看 |