aspectj切面织入
一、介紹
AspectJ 是一個(gè) AOP 的具體實(shí)現(xiàn)框架。AOP(Aspect Oriented Programming)即面向切面編程,可以通過預(yù)編譯方式和運(yùn)行期動態(tài)代理實(shí)現(xiàn)在不修改源代碼的情況下給程序動態(tài)統(tǒng)一添加功能的一種技術(shù)。AspectJ不但可以通過預(yù)編譯方式(CTW)和運(yùn)行期動態(tài)代理的方式織入切面,還可以在載入(Load Time Weaving, LTW)時(shí)織入。AspectJ 擴(kuò)展了Java,定義了一些專門的AOP語法。
靜態(tài)代理唯一的缺點(diǎn)就是我們需要對每一個(gè)方法編寫我們的代理邏輯,造成了工作的繁瑣和復(fù)雜。AspectJ就是為了解決這個(gè)問題,在編譯成class字節(jié)碼的時(shí)候在方法周圍加上業(yè)務(wù)邏輯。復(fù)雜的工作由特定的編譯器幫我們做,而 aspectj-maven-plugin 插件即可幫我們完成靜態(tài)編譯代理。
aspectj-maven-plugin 的相關(guān)介紹 aspectj-maven-plugin 的相關(guān)介紹, 對應(yīng)的GitHub 地址 GitHub地址
aspectj-maven-plugin 插件是在 編譯階段 compile 對文件進(jìn)行增強(qiáng),可以從 生成的.class 文件可以看出.
二、靜態(tài)編譯代理
靜態(tài)編譯代理依賴ajc編譯器,通過maven插件支持。
- 靜態(tài)代理所需要的配置:aspectj-maven-plugin插件
- 并且如果切面來源于三方j(luò)ar包并且需要對當(dāng)前項(xiàng)目代碼做代理,那么需要通過配置指定插件中的AspectLibrary屬性來指定三方包來達(dá)到當(dāng)前項(xiàng)目的增強(qiáng),切面就是定義在當(dāng)前項(xiàng)目則無需此操作
- 依賴AspectjTool 工具包
maven插件如下所示:
<plugin><groupId>org.codehaus.mojo</groupId><artifactId>aspectj-maven-plugin</artifactId><version>1.10</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding><complianceLevel>1.8</complianceLevel><verbose>true</verbose><showWeaveInfo>true</showWeaveInfo><aspectLibraries><aspectLibrary><groupId>com.example.pastor</groupId><artifactId>metric-reportor</artifactId></aspectLibrary></aspectLibraries></configuration><executions><execution><goals><goal>compile</goal><goal>test-compile</goal></goals></execution></executions> </plugin>1、案例一
(1)pom.xml
<dependencies><!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.13</version></dependency><!-- 這個(gè)包不用引入,否則切面織入失敗 --><!--<dependency><groupId>org.aspectj</groupId><artifactId>aspectjtools</artifactId><version>1.8.13</version></dependency>--></dependencies><!--<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>--><build><plugins><plugin><groupId>org.codehaus.mojo</groupId><artifactId>aspectj-maven-plugin</artifactId><version>1.11</version><configuration><complianceLevel>1.8</complianceLevel><source>1.8</source><target>1.8</target><showWeaveInfo>true</showWeaveInfo><Xlint>ignore</Xlint><encoding>UTF-8</encoding><!-- 注意:IDEA下這個(gè)值要設(shè)置為false,否則運(yùn)行程序時(shí)IDEA會再次編譯,導(dǎo)致aspectj-maven-plugin編譯的結(jié)果被覆蓋 --><skip>false</skip></configuration><executions><execution><configuration><skip>false</skip></configuration><goals><goal>compile</goal></goals></execution></executions></plugin></plugins></build>(2)業(yè)務(wù)方法
package com.scy.example.aspectj;public class UserServiceEnd {public void printLog() {System.out.println(" no param.....");} }(3)切面代碼
package com.scy.example.aspectj;import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before;@Aspect public class MethodEndAspect {@Before("execution(* com.scy.example.aspectj.UserServiceEnd.printLog())")public void setStartTimeInThreadLocal(JoinPoint joinPoint) {System.out.println("before ...");}}(4)編譯
輸入 編譯命令,mvn clean compile
PS E:\IdeaProjectSun\example> mvn clean compile [INFO] Scanning for projects... [INFO] [INFO] --------------------------< com.scy:example >--------------------------- [INFO] Building example 0.0.1-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ example --- [INFO] Deleting E:\IdeaProjectSun\example\target [INFO] [INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ example --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 1 resource [INFO] Copying 16 resources [INFO] [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ example --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 8 source files to E:\IdeaProjectSun\example\target\classes [INFO] [INFO] --- aspectj-maven-plugin:1.11:compile (default) @ example --- [INFO] Showing AJC message detail for messages of types: [error, warning, fail] [INFO] Join point 'method-execution(void com.scy.example.aspectj.UserServiceEnd.printLog())' in Type 'com.scy.example.aspectj.UserServiceEnd' (UserServiceEnd.java:4 ) advised by before advice from 'com.scy.example.aspectj.MethodEndAspect' (MethodEndAspect.java:11) [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 2.306 s [INFO] Finished at: 2022-09-02T14:41:07+08:00 [INFO] ------------------------------------------------------------------------(5)查看反編譯的class文件
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) //package com.scy.example.aspectj;import org.aspectj.lang.JoinPoint; import org.aspectj.runtime.reflect.Factory;public class UserServiceEnd {public UserServiceEnd() {}public void printLog() {JoinPoint var1 = Factory.makeJP(ajc$tjp_0, this, this);MethodEndAspect.aspectOf().setStartTimeInThreadLocal(var1);System.out.println(" no param.....");}static {ajc$preClinit();} }(6)運(yùn)行結(jié)果
before ...no param.....2、案例二
對pom.xml 進(jìn)行優(yōu)化,其他不變。
<dependencies><!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.13</version></dependency><!-- https://mvnrepository.com/artifact/org.aspectj/aspectjtools --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjtools</artifactId><version>1.8.13</version></dependency></dependencies><!--<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>--><build><plugins><plugin><groupId>org.codehaus.mojo</groupId><artifactId>aspectj-maven-plugin</artifactId><version>1.11</version><configuration><complianceLevel>1.8</complianceLevel><source>1.8</source></configuration><executions><execution><goals><goal>compile</goal><goal>test-compile</goal></goals></execution></executions></plugin></plugins></build>三、LoadTimeWeave加載期織入增強(qiáng)
加載類文件時(shí)通過instrument包去修改字節(jié)碼來插入增強(qiáng)邏輯
- 首先要通過@EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.AUTODETECT)
- 其次要在項(xiàng)目啟動參數(shù)上要通過探針指定instrument包來動態(tài)修改織入
- 在spring boot應(yīng)用加上此配置來讓應(yīng)用去讀取META-INF目錄下的aop.xml讀取切面已經(jīng)要織入的路徑配置(目前此配置在監(jiān)控的sdk中我已經(jīng)定義配置好)
工程配置類開啟LTW
@EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.AUTODETECT) 1java探針啟動參數(shù)
-javaagent:spring-instrument-5.2.5.RELEASE.jar 1然后在類路徑下META-INF下面提供aop描述文件aop.xml,描述待織入的類路徑和切面類所在位置
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd"> <aspectj><weaver options="-showWeaveInfo -verbose"><include within="com.example.ltw.entity.*"/><include within="com.example.ltw.service.*"/></weaver><aspects><aspect name="com.example.ltw.ProfilingAspect"/><aspect name="com.qiyi.pastor.metricreportor.report.PastorReportAop"/></aspects> </aspectj>四、小結(jié)
- Aspectj并不是動態(tài)的在運(yùn)行時(shí)生成代理類,而是在編譯的時(shí)候就植入代碼到class文件
- 由于是靜態(tài)織入的,所以性能相對來說比較好
- Aspectj不受類的特殊限制,不管方法是private、或者static、或者final的,都可以代理
- Aspectj不會代理除了限定方法之外任何其他諸如toString(),clone()等方法
五、參考
https://blog.csdn.net/healist/article/details/108824428
基于使用AspectJ實(shí)現(xiàn)AOP,注解AOP開發(fā)(基于xml文件、基于注解)_杭州小哥哥的博客-CSDN博客
總結(jié)
以上是生活随笔為你收集整理的aspectj切面织入的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何为服务网格选择入口网关_理解服务网格
- 下一篇: cips2016+学习笔记︱NLP中的消