第九讲--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()");
}
}

浙公网安备 33010602011771号