日韩性视频-久久久蜜桃-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 | 日本公妇乱淫免费视频一区三区 | 午夜视频入口 | 伊人久久亚洲综合 | 双性受孕h堵精大肚生子 | 久久久国产一区二区三区 | 国产无遮挡裸体免费视频 | 精品一区二区精品 | 亚洲色图36p | 亚洲视频精品在线 | 影院一区 | 1024精品一区二区三区日韩 | 污网站在线观看免费 | 久久国产综合 | 手机电影在线观看 | xxx久久| 免费黄色大片 | 亚洲经典视频在线观看 | 成人免费黄色片 | 99久久久无码国产精品免费麻豆 | 绯色av一区二区三区高清 | 中文字幕精品一区二区三区精品 | 亚洲GV成人无码久久精品 | 欧美在线你懂的 | 国产成人小视频在线观看 | a√天堂资源在线 | 成人免费91| 天堂网中文在线观看 | 成人久久久精品国产乱码一区二区 | 亚洲黄色av网站 | 台湾a级艳片潘金莲 | 久久久中文网 | 天天射天天拍 | 韩国三色电费2024免费吗怎么看 | 在线视频福利 | 秋霞在线观看秋 | 六月婷婷网 | 精品久久无码中文字幕 | 免费的毛片网站 | 欧美在线一二三四区 | 欧美影视| 色偷偷噜噜噜亚洲男人的天堂 | 三级国产在线 | 国产日本一区二区 | 午夜免费网站 | 麻豆一二三区 | 97精品久久久 | 美女被草出白浆 | 一区二区三区日韩在线 | 91激情在线观看 | 欧美日本精品 | 伊人国产在线观看 | 久久久久久久久久久久久久久久久久久久 | 欧美日韩www | 精品不卡一区二区三区 | 亚色影库 | 黄色片网站在线观看 | av五十路| 国内偷拍第一页 | 精品99在线 | 亚洲不卡视频在线观看 | 少妇无码一区二区三区免费 | 国产精品乱码久久久久 | 日韩成人免费在线 | 人妻妺妺窝人体色www聚色窝 | 男人添女人荫蒂国产 | 明里柚番号 | 先锋影音色 | 国产一及毛片 | 欧洲国产精品 | 高清毛片aaaaaaaaa郊外 | 一级生活毛片 | 久久亚洲在线 | 亚洲高清精品视频 | 动漫精品一区一码二码三码四码 | 人民的名义第二部 | 91福利视频免费观看 | 欧美精品videos另类 | 久久久久亚洲av无码a片 | 超碰综合在线 | 国产91热爆ts人妖在线 | 黄色日批 | 成人网页 | 五月天小说网 | 香蕉网站在线 | www五月| 欧美一区二区视频 | 一级精品视频 | 亚洲AV无码国产精品国产剧情 | 国产精品麻豆一区二区三区 | 精品一区二区三区蜜桃 | 日日干综合 | 97精品人人妻人人 | 天天拍天天操 | 先锋影音av资源在线 | 国产黄在线免费观看 | 欧美亚洲日本国产 | 美妇av| 亚洲免费不卡视频 |