Aspectj是Eclipse基金会下的子项目,AspectJ提供了两种方式实现切面代码织入
编绎期织入:分为三种情况
编绎class文件时织入,通过ajc代替javac在java源文件compile成class时,通过扫描编绎aspectj注解或.aj文件,把切面切入到切点表达式指定的连接点,依赖aspectjtools包的ajc。
编绎后织入,依赖ajc,向javac编绎过的class或jar文件织入切面
类加载时织入,不依赖ajc,在类加载时织入切面,依赖aspectjweaver.jar,需要在jvm启动时设置java agent
运行时织入:有两种实现方式
jdk动态代理
利用字节码增强技术动态代理(CGLib)
本文是在使用编绎class文件织入实践介绍
aspectJ提供了两种切面的实现方式
基于.aj文件描述
基于java注解
关于aspectJ技术的详解,参考我们这篇文章:http://blog.51cto.com/5914679/2094025
以下文章的关注点是:多模块maven项目使用AspectJ编绎class时织入
在单模块项目中使用AspectJ的编绎期织入特性时,只需要在pom文件加入aspectj依赖和aspectj编绎插件即可:
<properties><aspectj.version>1.8.9</aspectj.version></properties><dependencyManagement> <dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>${aspectj.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <version>${aspectj.version}</version> </dependency> </dependencies><dependencyManagement> <dependencies><dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId></dependency><dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId></dependency></dependencies><plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.10</version> <configuration> <source>1.8</source> <target>1.8</target> <complianceLevel>1.8</complianceLevel> <XaddSerialVersionUID>true</XaddSerialVersionUID> <showWeaveInfo>true</showWeaveInfo> </configuration> <executions> <execution> <id>compile_with_aspectj</id> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>test-compile_with_aspectj</id> <goals> <goal>test-compile</goal> </goals> </execution> </executions> </plugin></plugins>
重新编绎项目,在生成的class文件里可以找到ajc生成的类
如果在多模块项目,在具体的某个子模块声明切面类,定义切点表达式,但是连接点切分散在各个其他模块时,ajc扫描具到切点表达式时,只会在本模块扫描对应的连接点,其他模块的连接点是没有办法编绎期切入切面,ajc是不会在编绎其他模块时再去扫描有没有某个切点表达式与当前连接点匹配的。为了解决这个问题,需要把ajc插件定义在parent pom文件里
<properties><aspectj.version>1.8.9</aspectj.version></properties><dependencyManagement> <dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>${aspectj.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <version>${aspectj.version}</version> </dependency> dependency> <groupId>com.xx.xx</groupId> <artifactId>xx_Aspectj</artifactId> <version>T.0.0.1-SNAPSHOT</version> </dependency> </dependencies><dependencyManagement><dependencies><dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId></dependency><dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId></dependency></dependencies><plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.10</version> <configuration> <source>1.8</source> <target>1.8</target> <complianceLevel>1.8</complianceLevel> <XaddSerialVersionUID>true</XaddSerialVersionUID> <showWeaveInfo>true</showWeaveInfo> <aspectLibraries> <aspectLibrary> <groupId>com.aiatss.xx</groupId> <artifactId>xx_Aspectj</artifactId> </aspectLibrary> </aspectLibraries> </configuration> <executions> <execution> <id>compile_with_aspectj</id> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>test-compile_with_aspectj</id> <goals> <goal>test-compile</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>com.xx.xx</groupId> <artifactId>xx_Aspectj</artifactId> <version>T.0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <version>${aspectj.version}</version> </dependency> </dependencies> </plugin> </plugins>
像上面的配置,如果子模块project_Aspectj也是作为子模块引用了parent pom文件,这时编绎时会报错:
The projects in the reactor contain a cyclic reference: Edge between 'Vertex{label='com.xx.xx:xx_Aspectj:T.0.0.1-SNAPSHOT'}' and 'Vertex{label='com.xx.xx:Framework:T.0.0.1-SNAPSHOT'}' introduces to cycle in the graph com.xx.xx:Framework:T.0.0.1-SNAPSHOT --> com.xx.xx:xx_Parent:T.0.0.1-SNAPSHOT --> com.xx.xx:xx_Aspectj:T.0.0.1-SNAPSHOT --> com.xx.xx:Framework:T.0.0.1-SNAPSHOT -> [Help 1]
这是一个cyclic reference问题,即是:xx_aspectj模块引用了parent pom项目,同时parent pom项目也引用了xx_aspectj项目,maven认为这是个错误,不应该出现,使用以下方式改造
首先把aspectj插件里的dependencies去掉,如下:
<properties><aspectj.version>1.8.9</aspectj.version></properties><dependencyManagement> <dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>${aspectj.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <version>${aspectj.version}</version> </dependency> dependency> <groupId>com.xx.xx</groupId> <artifactId>xx_Aspectj</artifactId> <version>T.0.0.1-SNAPSHOT</version> </dependency> </dependencies><dependencyManagement><dependencies><dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId></dependency><dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId></dependency></dependencies><plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.10</version> <configuration> <source>1.8</source> <target>1.8</target> <complianceLevel>1.8</complianceLevel> <XaddSerialVersionUID>true</XaddSerialVersionUID> <showWeaveInfo>true</showWeaveInfo> <aspectLibraries> <aspectLibrary> <groupId>com.aiatss.xx</groupId> <artifactId>xx_Aspectj</artifactId> </aspectLibrary> </aspectLibraries> </configuration> <executions> <execution> <id>compile_with_aspectj</id> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>test-compile_with_aspectj</id> <goals> <goal>test-compile</goal> </goals> </execution> </executions> </plugin> </plugins>
然后在xx_AspectJ子项目里屏蔽parent pom的插件,如下:
<plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.10</version> <configuration> <source>1.8</source> <target>1.8</target> <complianceLevel>1.8</complianceLevel> <XaddSerialVersionUID>true</XaddSerialVersionUID> <showWeaveInfo>true</showWeaveInfo> </configuration> <executions> <execution> <id>compile_with_aspectj</id> <phase>none</phase> </execution> <execution> <id>test-compile_with_aspectj</id> <phase>none</phase> </execution> </executions> </plugin> </plugins>
这是,如果xx_AspectJ项目要引用其他公共子模块时(比例:xx_common 、xx_repository)项目时,怎样么办?只能在xx_common、xx_repository项目中禁用来自parent pom AspectJ插件了,如此xx_AspectJ模块里的切面就无法切入xx_common、xx_repository项目的连接点了