第九讲--AOP实现之AspectJ(编译器增强)
第九讲-AOP实现之AspectJ(编译器增强)
该讲使用AspectJ来演示AOP的动态代理(我这里使用JDK1.8来演示)
首先导入相关依赖:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
并加入相关配置(从官网拷贝过来的,大致就是编译出来的目标类版本等等):
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.14.0</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<source>8</source>
<target>8</target>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<Xlint>ignore</Xlint>
<encoding>UTF-8</encoding>
</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>
编写一个服务类:
package com.cherry.chapter2.a09;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyService {
private static final Logger log = LoggerFactory.getLogger(MyService.class);
public void foo(){
log.debug("foo()");
}
}
编写一个切面类,为MyService的foo方法做前置增强
@Aspect
public class MyAspect {
private static final Logger log = LoggerFactory.getLogger(MyService.class);
@Before("execution(* com.cherry.chapter2.a09.MyService.foo())")
public void before(){
log.debug("before()");
}
}
注意将该类所在的模块使用maven工具编译一下,而不是使用IDEA的编译按钮,如下面的所示(我的是模块chapter2):
然后编写主方法直接运行测试:
@SpringBootApplication
public class A09Application {
private static final Logger log = LoggerFactory.getLogger(A09Application.class);
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(A09Application.class);
MyService service = new MyService();
log.debug("service class:{}",service.getClass());
service.foo();
context.close();
}
}
运行结果如下:
2024-07-26 18:29:00.109 DEBUG 7444 --- [ main] com.cherry.chapter2.a09.A09Application : service class:class com.cherry.chapter2.a09.MyService
2024-07-26 18:29:00.110 DEBUG 7444 --- [ main] com.cherry.chapter2.a09.MyService : before()
2024-07-26 18:29:00.111 DEBUG 7444 --- [ main] com.cherry.chapter2.a09.MyService : foo()
我们发现这个做增强的就是这个本类的对象,而不是所谓的xxxcgLibProxyXXX(也就是说做前置增强并没有使用到代理),这说明了AOP的实现不止代理。
此处的代理使用的是AspectJ编译器增强,这个增强的的逻辑是把我们的目标类的字节码文件进行了改写,并且加入了前置增强,如下面就是改写后的MyService.class:
public class MyService {
private static final Logger log = LoggerFactory.getLogger(MyService.class);
public MyService() {
}
public void foo() {
MyAspect.aspectOf().before();
log.debug("foo()");
}
我们发现,编译后的目标类的方法前多了一个方法的调用,该方法的作用就是找到对应的前置通知,然后调用方法通知方法。
既然classs都被改写了,那还需要目标代理吗?就不需要了,况且也和Sprign容器也就没什么关系了,注意看我写的目标类,类上并没有加上@Component
注解。这里来演示一下,不使用容器直接运行测试一下:
package com.cherry.chapter2.a09;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class A09Application {
private static final Logger log = LoggerFactory.getLogger(A09Application.class);
public static void main(String[] args) {
// ConfigurableApplicationContext context = SpringApplication.run(A09Application.class);
// MyService service = new MyService();
new MyService().foo();
// log.debug("service class:{}",service.getClass());
// service.foo();
// context.close();
}
}
18:44:52.233 [main] DEBUG com.cherry.chapter2.a09.MyService - before()
18:44:52.238 [main] DEBUG com.cherry.chapter2.a09.MyService - foo()
我们发现,不借助Spring容器也实现了目标类的功能增强!
这种使用AspectJ做方法增强有什么好处呢?可以突破一些代理的限制,因为代理本质上是通过方法重写来实现的,那么目标类是一个静态方法,动态代理能做增强吗?显然是不能的,但是AspectJ编译器增强是可以的,例如(注意使用maven cmopile重新编译一下):
public class MyService {
private static final Logger log = LoggerFactory.getLogger(MyService.class);
public static void foo(){
log.debug("foo()");
}
}
18:50:57.741 [main] DEBUG com.cherry.chapter2.a09.MyService - before()
18:50:57.745 [main] DEBUG com.cherry.chapter2.a09.MyService - foo()
我们发现,使用AspectJ编译器增强是可以实现静态方法的功能增强的。最后我们再看一下目标类反编译后的字节码文件:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
public class MyService {
private static final Logger log = LoggerFactory.getLogger(MyService.class);
public MyService() {
}
public static void foo() {
MyAspect.aspectOf().before();
log.debug("foo()");
}
}
分类:
Spring 高级49讲
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构