之前我们介绍了字节码增强的一些实现,如果想在业务代码中处理一些具有横切性质的系统级服务,如日志收集、事务管理、安全检查、缓存、对象池管理等时,开发人员需要深入研究字节码相关技术,编写业务代码时编写大量字节码重复相关逻辑,后续更不好维护。
面向切面的编程(Aspect-Oriented Programming,AOP) 是一种编程范式,旨在通过允许横切关注点的分离,提高模块化。AOP要实现的是在我们写的代码的基础上进行一定的包装,如在方法执行前、或执行后、或是在执行中出现异常后这些地方进行拦截处理或叫做增强处理。 AOP允许开发者将横切关注点(跨越多个模块的共同逻辑)与主要业务逻辑分离,以便更有效地管理和重用切面逻辑。AOP最早是AOP联盟的组织提出的,指定的一套规范。在AOP中,两个主要的实现框架是AspectJ和Spring AOP。本文将介绍AOP的概念,深入探讨AspectJ和Spring AOP,以及通过实例演示这两者的应用。
我们把这些术语串联到一起,方便理解
AspectJ全称是Eclipse AspectJ, 其官网地址是:www.eclipse.org/aspectj/,目前最新版本为:1.9.7
AspectJ是一个功能强大的切面编程框架,支持在编译时和运行时织入切面逻辑。它通过Java语言的扩展来支持切面的声明式定义,引入了新的关键字和语法元素。AspectJ支持多种通知类型,包括前置、后置、环绕、返回和异常通知,以及静态织入和动态织入。
引用官网描述:
a seamless aspect-oriented extension to the Javatm programming language(一种基于Java平台的面向切面编程的语言) Java platform compatible(兼容Java平台,可以无缝扩展) easy to learn and use(易学易用)
AspectJ可以单独使用,也可以整合到其它框架中。单独使用AspectJ时需要使用专门的编译器ajc。
java的编译器是javac,AspectJ的编译器是ajc,aj是首字母缩写,c即compiler。
了解AspectJ应用到java代码的过程(这个过程称为织入),对于织入这个概念,可以简单理解为aspect(切面)应用到目标函数(类)的过程。
对于这个过程,一般分为动态织入和静态织入:
使用AspectJ有两种方法:
下面我们使用@AspectJ注解写个在方法执行前后打印日志的例子。
java复制代码public class ProductService {
public void saveProduct(String productName) {
System.out.println("Saving product: " + productName);
}
public String getProduct(String productId) {
System.out.println("Getting product: " + productId);
return "Product Details";
}
}
xml复制代码
org.codehaus.mojo
aspectj-maven-plugin
1.8
1.8
1.8
1.8
true
true
ignore
UTF-8
compile
test-compile
pom复制代码
org.aspectj
aspectjrt
1.8.7
org.aspectj
aspectjweaver
1.8.7
java复制代码@Aspect
public class LoggingAspect {
@Pointcut("execution(public * com.aspectj.service.*.*(..))")
protected void logMethods() {
}
// 前置通知,在方法执行前记录日志
@Before("logMethods()")
public void before(JoinPoint pjp) throws Throwable {
System.out.println("Entering method: " + pjp.getSignature().getName());
}
@After("logMethods()")
public void after(JoinPoint pjp) throws Throwable {
System.out.println("Exiting method: " + pjp.getSignature().getName());
}
}
这是最简单的使用方式,在编译期的时候进行织入,这样编译出来的 .class 文件已经织入了我们的代码,在 JVM 运行的时候其实就是加载了一个普通的被织入了代码的类。
Spring的一个关键组件是AOP框架。 虽然Spring IOC容器不依赖于AOP(意味着你不需要在IOC中依赖AOP),但AOP为Spring IOC提供了非常强大的中间件解决方案。
Spring AOP 是基于动态代理来实现,默认如果使用接口的,用JDK提供的动态代理实现,如果是方法则使用CGLIB实现。
java复制代码import org.springframework.stereotype.Service;
@Service
public class ProductService {
public void saveProduct(String productName) {
System.out.println("Saving product: " + productName);
}
public String getProduct(String productId) {
System.out.println("Getting product: " + productId);
return "Product Details";
}
}
java复制代码@Component
public class AppRunner implements CommandLineRunner {
@Autowired
private ProductService productService;
@Override
public void run(String... args) {
productService.saveProduct("Sample Product");
productService.getProduct("123");
}
}
xml复制代码
org.springframework.boot
spring-boot-starter-aop
java复制代码import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
@Pointcut("execution(* com.demo.service.*.*(..))")
private void logMethods() {}
@Before("logMethods()")
public void beforeAdvice() {
System.out.println("Entering method...");
}
@After("logMethods()")
public void afterAdvice() {
System.out.println("Exiting method...");
}
}
这个示例展示了如何使用 Spring AOP 和注解在方法调用前后添加日志记录的功能。通过定义切面、切入点和通知,你可以轻松地实现横切关注点的逻辑。
这个表格总结了AspectJ和Spring AOP在不同方面的区别。
特性/方面 |
AspectJ |
Spring AOP |
实现方式 |
独立的切面编程框架,扩展了Java语法 |
Spring框架的一部分,基于动态代理和字节码增强技术 |
功能复杂性 |
提供更高级的切面编程能力,支持复杂的切面逻辑 |
更专注于常见的切面功能,适用于简单的切面逻辑 |
依赖性 |
独立使用,需要AspectJ编译器或插件 |
与Spring框架集成,依赖于Spring框架 |
织入方式 |
支持编译时织入和运行时织入 |
主要使用运行时织入,依赖于动态代理和字节码增强技术 |
使用场景 |
适用于复杂切面逻辑的场景,高要求 |
适用于通用切面需求,轻量级解决方案 |
依赖性注入 |
主要关注切面编程,不直接支持依赖性注入 |
可与Spring的依赖性注入机制集成,支持切面中使用其他Spring功能 |
性能 |
编译期织入,性能较好 |
基于动态代理来实现的,在容器启动时需要生成代理实例,在方法调用上也会增加栈的深度,性能不如AspectJ |
虽然字节码增强技术本身已经提供了一种在代码层面进行修改和增强的能力,但是在某些情况下,使用AOP(Aspect-Oriented Programming)仍然是有价值的。以下是一些理由:
虽然字节码增强技术在某些情况下可以实现类似的功能,但AOP提供了更高层次的抽象和更好的可维护性,使开发者能够更轻松地管理和重用横切关注点的逻辑。在实际开发中,使用AOP和字节码增强技术的组合可以根据具体情况来平衡开发效率和维护性。