spring 上的 aop 性能(idk,aspectj)
aop performance on spring (idk, aspectj)
我尝试在 Spring 框架 4.1.6 和
上测试 AOP 的性能
AOP 方法很干净,jdk 动态代理和 aspectJ。
我向他们提出了一到五个简单的建议,并检查了每个建议的经过时间。
结果:
jdk动态代理:
- 方面 1:2.499 秒
- 纵横比 2:2.574
- 纵横比 3:2.466
- 4 方面:2.436
- 纵横比 5:2.563
aspectJ (ctw):
- 方面 1:2.648
- 纵横比 2:2.562
- 纵横比 3:2.635
- 4 方面:2.520
- 纵横比 5:2.574
干净(无方面):
- 方面 1:2.699
- 纵横比 2:2.513
- 纵横比 3:2.527
- 4 方面:2.458
- 纵横比 5:2.402
在测试它们之前,我预计 AspectJ (ctw) 会比 Jdk 动态代理更快,因为 AspectJ 修改了字节码。但是即使它们之间没有性能差异也是错误的。
所以,我检查了目标 class(.class) modified to recognize that AspectJ Compiler used and found bytecode modified.
这里,我有一个问题:
它们之间有什么性能差异吗? (idk动态代理,aspectj,无aop)
我的代码:
public class HelloAOP {
public static void main(String [] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/application-context.xml");
Order order = (Order) ctx.getBean("orderImpl");
SimpleDateFormat format = new SimpleDateFormat("mm:ss.SSS");
StopWatch watch = new StopWatch();
watch.start();
order.placeOrder();
watch.stop();
System.out.println("Elapsed: " + format.format(watch.getTotalTimeMillis()));
}
}
目标:
@Service
public class OrderImpl implements Order {
public void placeOrder() {
System.out.println("::Target Object");
for(long i = 0; i < 5000000000L; i++);
}
}
看点:
@Aspect
@Component
public class Aspect1 {
@Before("execution(* com.cafe.beans.impl.OrderImpl.placeOrder())")
public void aspect() {
System.out.println("Aspect 1 *");
}
}
pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.1.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.6</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.6</version>
</dependency>
<build>
<finalName>testAop</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>3.3</source>
<target>3.3</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Tests.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<complianceLevel>1.8</complianceLevel>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
您没有看到任何差异,您不应该感到惊讶,因为您只是在测量一个方法调用。 99.9% 的测量时间是您方法中的循环。因此,您没有衡量正确的事情。你应该反过来做,也许类似于我所做的 here:
- 该方法应该什么都不做或几乎什么也不打印。
- 你应该测量重复调用方面建议方法的总时间,因为你想了解应用方面的开销,而不是方法体运行时(方法体在你的方面保持不变)。
现在您可以将 Spring AOP 与 AspectJ 的性能进行比较,应该会发现 AspectJ 更胜一筹。一些注意事项:
- 我希望您知道您需要更改 Spring 配置以便从 Spring AOP 切换到 AspectJ,反之亦然。例如。如果您一直使用 AspectJ Maven 插件进行构建,您将使用编译时 AspectJ 织入,无论您是否配置 Spring 以使用 Spring AOP 或 AspectJ 通过加载时织入(如所述)在 Spring 手册中,第 10.8 Using AspectJ with Spring applications.
部分
- 你应该测量不同类型的切入点和建议,例如
@Before
/@After
对比 @Around
,(不)通过 this()
、target()
或 args()
等使用参数绑定
- 另请注意,您的示例代码在 class 而不是接口上使用切入点。 JDK 动态代理不能直接在 classes 上工作,但只能在接口上工作。为了在 classes 上应用 Spring AOP,您需要将 CGLIB 作为 Spring 中的依赖项,否则它根本无法工作。 编辑: 好的,您的 class 实现了
Order
接口,因此它可能仍然可以与 JDK 动态代理一起使用。
我尝试在 Spring 框架 4.1.6 和
上测试 AOP 的性能AOP 方法很干净,jdk 动态代理和 aspectJ。
我向他们提出了一到五个简单的建议,并检查了每个建议的经过时间。
结果:
jdk动态代理:
- 方面 1:2.499 秒
- 纵横比 2:2.574
- 纵横比 3:2.466
- 4 方面:2.436
- 纵横比 5:2.563
aspectJ (ctw):
- 方面 1:2.648
- 纵横比 2:2.562
- 纵横比 3:2.635
- 4 方面:2.520
- 纵横比 5:2.574
干净(无方面):
- 方面 1:2.699
- 纵横比 2:2.513
- 纵横比 3:2.527
- 4 方面:2.458
- 纵横比 5:2.402
在测试它们之前,我预计 AspectJ (ctw) 会比 Jdk 动态代理更快,因为 AspectJ 修改了字节码。但是即使它们之间没有性能差异也是错误的。
所以,我检查了目标 class(.class) modified to recognize that AspectJ Compiler used and found bytecode modified.
这里,我有一个问题: 它们之间有什么性能差异吗? (idk动态代理,aspectj,无aop)
我的代码:
public class HelloAOP {
public static void main(String [] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/application-context.xml");
Order order = (Order) ctx.getBean("orderImpl");
SimpleDateFormat format = new SimpleDateFormat("mm:ss.SSS");
StopWatch watch = new StopWatch();
watch.start();
order.placeOrder();
watch.stop();
System.out.println("Elapsed: " + format.format(watch.getTotalTimeMillis()));
}
}
目标:
@Service
public class OrderImpl implements Order {
public void placeOrder() {
System.out.println("::Target Object");
for(long i = 0; i < 5000000000L; i++);
}
}
看点:
@Aspect
@Component
public class Aspect1 {
@Before("execution(* com.cafe.beans.impl.OrderImpl.placeOrder())")
public void aspect() {
System.out.println("Aspect 1 *");
}
}
pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.1.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.6</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.6</version>
</dependency>
<build>
<finalName>testAop</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>3.3</source>
<target>3.3</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Tests.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<complianceLevel>1.8</complianceLevel>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
您没有看到任何差异,您不应该感到惊讶,因为您只是在测量一个方法调用。 99.9% 的测量时间是您方法中的循环。因此,您没有衡量正确的事情。你应该反过来做,也许类似于我所做的 here:
- 该方法应该什么都不做或几乎什么也不打印。
- 你应该测量重复调用方面建议方法的总时间,因为你想了解应用方面的开销,而不是方法体运行时(方法体在你的方面保持不变)。
现在您可以将 Spring AOP 与 AspectJ 的性能进行比较,应该会发现 AspectJ 更胜一筹。一些注意事项:
- 我希望您知道您需要更改 Spring 配置以便从 Spring AOP 切换到 AspectJ,反之亦然。例如。如果您一直使用 AspectJ Maven 插件进行构建,您将使用编译时 AspectJ 织入,无论您是否配置 Spring 以使用 Spring AOP 或 AspectJ 通过加载时织入(如所述)在 Spring 手册中,第 10.8 Using AspectJ with Spring applications. 部分
- 你应该测量不同类型的切入点和建议,例如
@Before
/@After
对比@Around
,(不)通过this()
、target()
或args()
等使用参数绑定 - 另请注意,您的示例代码在 class 而不是接口上使用切入点。 JDK 动态代理不能直接在 classes 上工作,但只能在接口上工作。为了在 classes 上应用 Spring AOP,您需要将 CGLIB 作为 Spring 中的依赖项,否则它根本无法工作。 编辑: 好的,您的 class 实现了
Order
接口,因此它可能仍然可以与 JDK 动态代理一起使用。