什么是AOP
AOP,全称是面向切面编程(Aspect-Oriented Programming)。
AOP是一种编程范式,其主要目标是提高模块化程度,以提高代码的可重用性和可维护性。
为什么需要AOP
在传统的面向对象编程(OOP)中,我们通常会将代码按照功能进行模块化。然而,有些功能(例如日志记录、事务管理、安全性检查等)可能会跨越多个模块,这些功能我们通常称之为"横切关注点"。在OOP中处理这些横切关注点通常会导致代码的重复和分散,这就是所谓的"代码污染"。
AOP的主要思想就是将这些横切关注点从业务逻辑代码中分离出来,单独进行模块化,然后在运行时将它们动态地"织入"到需要的业务逻辑中。这样,我们就可以将关注点的代码集中管理,提高代码的可重用性和可维护性。
Spring AOP 的底层实现原理
Spring AOP使用了代理模式,通过在运行时创建代理对象来实现切面的织入。这样,当调用一个被代理的方法时,Spring AOP就可以在方法调用前后插入切面代码,实现例如日志记录、事务管理等功能。
AOP的核心概念
- 横切关注点-Crosscutting Concerns 横切关注点是指软件系统中跨越多个模块的功能和关注点。例如日志记录、安全检测、权限控制等。
- 切面-Aspect 切面是AOP的基本构建块,它是对横切关注点的模块化表示。切面可以包含一些通知(Advice)和切入点(Pointcut)。切面是将横切关注点封装起来的模块。
- 连接点-JoinPoint 连接点是在应用程序中你想要插入切面的点。在Spring AOP中,连接点总是表示一个方法的执行。
- 通知-Advice
通知是切面模块的具体实现,它定义了切面需要完成的工作。Spring AOP支持五种类型的通知
- 前置通知(Before)
- 后置通知(After)
- 返回后通知(After Returning)
- 抛出异常后通知(After Throwing)
- 环绕通知(Around)。
- 切入点-PointCut 切入点是一组连接点的集合,它定义了通知应该在哪些连接点上执行。 Spring AOP使用AspectJ的切入点表达式语言来定义切入点。
- 目标对象-Target Object 目标对象是被一个或者多个切面所通知的对象。也就是包含连接点的对象。
- 代理-Proxy
代理是一个被AOP框架动态创建的对象,它用来实现切面代码的插入。
在Spring AOP中,代理有两种
- JDK动态代理
- CGLIB代理。
- 织入-Weaving 织入是将切面插入到目标对象以创建新的代理对象的过程。织入可以在编译时(使用AspectJ编译器),类加载时,或者运行时(如Spring AOP)进行。
如何使用AOP
好的,让我们以日志记录为例,来看一下如何使用Spring AOP进行面向切面编程。
识别横切关注点:在这个例子中,我们的横切关注点是日志记录,因为我们希望在每个方法执行前后都记录日志。
定义切面:我们可以创建一个新的Java类,并使用@Aspect
注解来定义这个类为一个切面:
@Aspect
@Component
public class LoggingAspect {
// ...
}
定义通知:在切面类中,我们可以定义一些通知方法。例如,我们可以定义一个前置通知和一个后置通知,分别在方法执行前后记录日志
代码语言:javascript复制@Aspect
@Component
public class LoggingAspect {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
logger.info("开始执行方法:{}", joinPoint.getSignature().getName());
}
@After("execution(* com.example.service.*.*(..))")
public void logAfter(JoinPoint joinPoint) {
logger.info("方法执行结束:{}", joinPoint.getSignature().getName());
}
}
定义切入点:在这个例子中,我们的切入点是com.example.service
包下的所有方法。我们使用execution
表达式来定义这个切入点,并在@Before
和@After
注解中直接使用。如果你希望在多个通知中复用同一个切入点,你可以使用@Pointcut
注解来定义一个切入点:
@Aspect
@Component
public class LoggingAspect {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}
@Before("serviceMethods()")
public void logBefore(JoinPoint joinPoint) {
logger.info("开始执行方法:{}", joinPoint.getSignature().getName());
}
@After("serviceMethods()")
public void logAfter(JoinPoint joinPoint) {
logger.info("方法执行结束:{}", joinPoint.getSignature().getName());
}
}
配置AOP:最后,我们需要在Spring的配置中启用AOP。如果你使用的是Spring Boot,那么AOP已经默认启用了。如果你使用的是传统的Spring,你可以在你的配置类中添加@EnableAspectJAutoProxy
注解来启用AOP:
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
// ...
}