@Aspect 注解是 Spring AOP (Aspect-Oriented Programming) 的核心注解之一,用于声明一个切面类。Spring 容器在启动时会解析和处理 @Aspect 注解,并将其转换为相应的代理对象,以实现 AOP 功能。
解析和处理流程:
-
容器启动: Spring 容器启动时,会扫描并加载 Bean 定义。
-
发现
@Aspect注解:- 如果在 XML 配置中启用了
<aop:aspectj-autoproxy/>,或者在 Java 配置类上使用了@EnableAspectJAutoProxy注解,Spring 容器会启用 AspectJ 自动代理。 - 启用自动代理后,容器会创建一个名为
AnnotationAwareAspectJAutoProxyCreator的BeanPostProcessor。 AnnotationAwareAspectJAutoProxyCreator会在 Bean 初始化阶段检查 Bean 是否带有@Aspect注解。
- 如果在 XML 配置中启用了
-
解析
@Aspect注解:- 如果发现 Bean 带有
@Aspect注解,AnnotationAwareAspectJAutoProxyCreator会解析该注解及其内部的切点 (Pointcut)、通知 (Advice) 等信息。 - 切点 (Pointcut): 使用
@Pointcut注解定义,指定了哪些连接点 (Join Point) 会被拦截。连接点通常是方法的执行。 - 通知 (Advice): 使用
@Before、@After、@AfterReturning、@AfterThrowing、@Around等注解定义,指定了在切点匹配的连接点上执行的操作。@Before: 在连接点之前执行。@After: 在连接点之后执行(无论是否发生异常)。@AfterReturning: 在连接点成功返回后执行。@AfterThrowing: 在连接点抛出异常后执行。@Around: 环绕通知,在连接点前后都可以执行,还可以控制目标方法的执行。
AnnotationAwareAspectJAutoProxyCreator会将解析出的切点和通知信息封装成Advisor对象。Advisor代表一个切面,包含了切点和通知。
- 如果发现 Bean 带有
-
创建代理对象:
- 对于需要被 AOP 增强的 Bean(即目标对象,Target Object),
AnnotationAwareAspectJAutoProxyCreator会为其创建代理对象。 - Spring AOP 使用两种代理方式:
- JDK 动态代理: 如果目标对象实现了接口,Spring 会使用 JDK 动态代理。代理对象实现了与目标对象相同的接口。
- CGLIB 代理: 如果目标对象没有实现接口,Spring 会使用 CGLIB 代理。代理对象是目标对象的子类。
- 代理对象拦截了对目标对象方法的调用,并根据
Advisor中的切点和通知信息,在方法执行前后执行相应的操作。
- 对于需要被 AOP 增强的 Bean(即目标对象,Target Object),
-
将代理对象放入容器:
AnnotationAwareAspectJAutoProxyCreator会将创建的代理对象放入 Spring 容器中,替换掉原来的目标对象。- 当其他 Bean 依赖于目标对象时,Spring 容器会注入代理对象,而不是原始的目标对象。
详细说明:
AnnotationAwareAspectJAutoProxyCreator: 这是 Spring AOP 的核心组件,它实现了BeanPostProcessor接口,负责解析@Aspect注解、创建代理对象等。Advisor: 代表一个切面,包含了切点和通知。Pointcut: 切点,定义了哪些连接点会被拦截。使用 AspectJ 的切点表达式语言 (Pointcut Expression Language) 来描述。Advice: 通知,定义了在切点匹配的连接点上执行的操作。Join Point: 连接点,程序执行过程中的一个点,例如方法的执行、异常的抛出等。Target Object: 目标对象,需要被 AOP 增强的 Bean。Proxy Object: 代理对象,Spring AOP 创建的代理对象,拦截了对目标对象方法的调用。
示例:
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
// 定义切点:拦截所有 com.example.service 包下的所有类的所有方法
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}
// 前置通知:在方法执行前记录日志
@Before("serviceMethods()")
public void beforeAdvice() {
System.out.println("Before method execution...");
}
// 后置通知:在方法执行后记录日志
@After("serviceMethods()")
public void afterAdvice() {
System.out.println("After method execution...");
}
}
在这个例子中:
@Aspect注解声明了LoggingAspect类是一个切面。@Pointcut注解定义了一个名为serviceMethods的切点,它匹配com.example.service包下所有类的所有方法。@Before和@After注解定义了两个通知,分别在方法执行前后记录日志。
当 Spring 容器启动时,会解析 @Aspect 注解,并为 com.example.service 包下的所有 Bean 创建代理对象。当这些 Bean 的方法被调用时,代理对象会拦截方法调用,并在方法执行前后执行 beforeAdvice 和 afterAdvice 方法。
总结流程图:
+---------------------+ +--------------------------------+ +---------------------+
| Spring 容器 |---->| AnnotationAwareAspectJAutoProxyCreator |---->| 目标对象 |
+---------------------+ +--------------------------------+ +---------------------+
| |
| 1. 发现 @Aspect 注解 |
| 2. 解析 @Aspect、@Pointcut、@Advice |
| 3. 创建 Advisor 对象 |
| |
|----------------------------------------|
| |
| 4. 创建代理对象 (JDK 或 CGLIB) |
| |
V V
+----------------+ +-----------------+
| 代理对象 | | 调用目标方法 |
+----------------+ +-----------------+
| |
+---------------------------+---------------------------+ |
| | | |
| @Before (执行前) | 目标方法执行 | @After (执行后) |
| | | |
+---------------------------+---------------------------+ |
|
<-----------------------------------+
1万+

被折叠的 条评论
为什么被折叠?



