@Aspect 注解是如何被解析和处理的

@Aspect 注解是 Spring AOP (Aspect-Oriented Programming) 的核心注解之一,用于声明一个切面类。Spring 容器在启动时会解析和处理 @Aspect 注解,并将其转换为相应的代理对象,以实现 AOP 功能。

解析和处理流程:

  1. 容器启动: Spring 容器启动时,会扫描并加载 Bean 定义。

  2. 发现 @Aspect 注解:

    • 如果在 XML 配置中启用了 <aop:aspectj-autoproxy/>,或者在 Java 配置类上使用了 @EnableAspectJAutoProxy 注解,Spring 容器会启用 AspectJ 自动代理。
    • 启用自动代理后,容器会创建一个名为 AnnotationAwareAspectJAutoProxyCreatorBeanPostProcessor
    • AnnotationAwareAspectJAutoProxyCreator 会在 Bean 初始化阶段检查 Bean 是否带有 @Aspect 注解。
  3. 解析 @Aspect 注解:

    • 如果发现 Bean 带有 @Aspect 注解,AnnotationAwareAspectJAutoProxyCreator 会解析该注解及其内部的切点 (Pointcut)、通知 (Advice) 等信息。
    • 切点 (Pointcut): 使用 @Pointcut 注解定义,指定了哪些连接点 (Join Point) 会被拦截。连接点通常是方法的执行。
    • 通知 (Advice): 使用 @Before@After@AfterReturning@AfterThrowing@Around 等注解定义,指定了在切点匹配的连接点上执行的操作。
      • @Before: 在连接点之前执行。
      • @After: 在连接点之后执行(无论是否发生异常)。
      • @AfterReturning: 在连接点成功返回后执行。
      • @AfterThrowing: 在连接点抛出异常后执行。
      • @Around: 环绕通知,在连接点前后都可以执行,还可以控制目标方法的执行。
    • AnnotationAwareAspectJAutoProxyCreator 会将解析出的切点和通知信息封装成 Advisor 对象。Advisor 代表一个切面,包含了切点和通知。
  4. 创建代理对象:

    • 对于需要被 AOP 增强的 Bean(即目标对象,Target Object),AnnotationAwareAspectJAutoProxyCreator 会为其创建代理对象。
    • Spring AOP 使用两种代理方式:
      • JDK 动态代理: 如果目标对象实现了接口,Spring 会使用 JDK 动态代理。代理对象实现了与目标对象相同的接口。
      • CGLIB 代理: 如果目标对象没有实现接口,Spring 会使用 CGLIB 代理。代理对象是目标对象的子类。
    • 代理对象拦截了对目标对象方法的调用,并根据 Advisor 中的切点和通知信息,在方法执行前后执行相应的操作。
  5. 将代理对象放入容器:

    • 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 的方法被调用时,代理对象会拦截方法调用,并在方法执行前后执行 beforeAdviceafterAdvice 方法。

总结流程图:

+---------------------+     +--------------------------------+     +---------------------+
|     Spring 容器     |---->| AnnotationAwareAspectJAutoProxyCreator |---->|      目标对象       |
+---------------------+     +--------------------------------+     +---------------------+
                                    |                                        |
                                    | 1. 发现 @Aspect 注解                |
                                    | 2. 解析 @Aspect、@Pointcut、@Advice |
                                    | 3. 创建 Advisor 对象                  |
                                    |                                        |
                                    |----------------------------------------|
                                    |                                        |
                                    | 4. 创建代理对象 (JDK 或 CGLIB)           |
                                    |                                        |
                                    V                                        V
                              +----------------+                      +-----------------+
                              |    代理对象     |                      |   调用目标方法    |
                              +----------------+                      +-----------------+
                                    |                                        |
       +---------------------------+---------------------------+            |
       |                           |                           |            |
       |   @Before (执行前)       |     目标方法执行        |   @After (执行后)     |
       |                           |                           |            |
       +---------------------------+---------------------------+            |
                                                                            |
                                         <-----------------------------------+

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰糖心书房

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值