如今java生态中spring大行其道,通常使用aspectj进行切面编程使用注解方式实现,比较少使用原生的aspectj编程,网上的资料也比较少。最近工做中须要封装redisson客户端提供统一的redis组件,主要就是实现耗时日志打印以及上报,压测支持等功能。为了不组件依赖spring的状况,使用了aspectj原生库编程。工程基于jdk1.8。java
aspectj定义(来自wiki):AspectJ是在PARC为Java编程语言建立的面向方面的编程扩展。它能够在Eclipse Foundation开源项目中使用,既能够单独使用,也能够集成到Eclipse中。redis
关于面向切面编程,这里再也不赘述,通常用于实现通用的功能,好比日志打印,权限控制等。aspectj经过定义切面,将spring
aspectj依赖两个核心库(aspectjrt,aspectjweaver),因此在须要在工程pom文件中添加一下依赖编程
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.9</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.9</version> </dependency>
要使aspectj织入功能生效还须要添加aspectj-maven-plugin插件,配置以下。数据结构
<build> <plugins> <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> <weaveDependencies> <weaveDependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> </weaveDependency> </weaveDependencies> </configuration> <executions> <execution> <goals> <!-- use this goal to weave all your main classes --> <goal>compile</goal> <!-- use this goal to weave all your test classes --> <!--<goal>test-compile</goal>--> </goals> </execution> </executions> </plugin> </plugins> </build>
aspectj能够选择织入的时期,主要分为三种:编译时,编译后,运行期。编译时织入只对织入代码在本工程的状况,编译后织入除了本工程代码还包括针对织入代码在第三方jar包状况,运行时织入只有在代码运行时才作动态切面。上面这个例子是编译后的配置,其中weaveDependencies配置了第三方jar包信息,只须要编译是织入能够不用配置。运行时织入参考(https://www.baeldung.com/aspectj)maven
切面类代码以下编程语言
/** * @date 2018/12/22 */ public aspect CommandAspect { /** * redis命令方法切面,全部redis命令都会通过 */ public pointcut callSendCommand(): execution (* org.redisson.command.CommandAsyncService.sendCommand(..)); /** * RedissonExpirable的全部子类方法切面,基本包含了redisson内置的经常使用数据结构 */ public pointcut callExpireSubClassMethod(): execution (* org.redisson.RedissonExpirable+.*(..)); Object around(): callSendCommand() { //long startNs = System.nanoTime(); Object result = proceed(); //AspectUtil.sendMetrics(startNs, thisJoinPoint); return result; } Object around(): callExpireSubClassMethod(){ Object result = proceed(); //AspectUtil.resetExpireTime(thisJoinPoint); return result; } }
对于熟悉注解方式实现的同窗能够发现,这种方式与注解方式十分相像,这里是实现了around,一样也支持before,after方式。在idea intellij调试时,没法在apsect类中断点,可是能够在其依赖的class类中断点,这对于咱们第一次编码的时候存在一些困扰。ide
编码完成后,使用mvn compile命令,实现代码织入,以后就能够进行调试了ui
参考文档:this
http://opoo.org/aspectj-compile-time-weaving/
https://www.baeldung.com/aspectj