Spring AOP的底层原理分析

本文深入探讨了Spring AOP中@Aspect注解实现的AOP功能背后的原理。通过示例展示了如何创建Aspect拦截类,并在CGLib动态代理下实现方法拦截。在调用实际方法前,会执行@Before、@After等注解的方法。SpringAOP通过CGLibAopProxy的DynamicAdvisedInterceptor在调用方法时进入拦截逻辑,最终由ReflectiveMethodInvocation.proceed()方法控制执行流程,实现方法拦截。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一般我们在开发springboot项目的时候通过在类上面标注@Aspect这个注释就可以实现一个AOP的功能,那这背后的实现原理是什么呢?

首先我们来写一个小样例

1、新建一个Aspect拦截类

@Component
@Aspect
public class MyAspect {
    @Pointcut("execution(* y.com.testapp.*.*(..))")
    public void point(){}

    @Before("point()")
    public void before(){
        System.out.println("before");
    }

    @After("point()")
    public void after(){
        System.out.println("after");
    }
}

2、新建一个普通类用来测试是否能进行拦截

@Component
public class C {
    public void sayHello(){
        System.out.println("hello");
    }
}

3、编写测试代码

@SpringBootApplication
public class TestappApplication {

   public static void main(String[] args) {
      ConfigurableApplicationContext context = SpringApplication.run(TestappApplication.class, args);
      C c=context.getBean(C.class);
      c.sayHello();
   }
}

执行查看结果

可以看到确实是在调用c.sayHello()方法过程中调用了拦截器

进一步分析看一下我们的这个c对象为什么在调用sayHello()的时候能够触发拦截器的拦截方法呢?首先看一下c这个对象的状态是什么样的

debug一下可以看到c实际上是一个代理对象,而且还是通过CGLib动态代理生成的。

接着执行会进入到org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept()方法里面来,而DynamicAdvisedInterceptor也就是实现了CGLib代理的MethodInterceptor这个接口,对CGBlib有了解的就知道这个接口的intercept()方法就是动态代理对象在调用方法的时候会进入到的一个拦截方法,这个方法和Spring AOP的@befor、@after、@around等方法还有点像呢。

这个方法里面主要有这么一个很重要的实现过程

创建一个CglibMethodInvocation对象并调用其proceed()方法,这个方法内容如下

public Object proceed() throws Throwable {
   try {
      return super.proceed();
   }
   catch (RuntimeException ex) {
      throw ex;
   }
   catch (Exception ex) {
      if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) {
         throw ex;
      }
      else {
         throw new UndeclaredThrowableException(ex);
      }
   }
}

主要就是调用父类的proceed()方法,再看一下这个类的父类是什么

也就是说上面的方法会进入到org.springframework.aop.framework.ReflectiveMethodInvocation#proceed()这个方法中去,看一下这个方法的内容

 

@Override
@Nullable
public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }

   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      // Evaluate dynamic method matcher here: static part will already have
      // been evaluated and found to match.
      InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
      if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      }
      else {
         // Dynamic matching failed.
         // Skip this interceptor and invoke the next in the chain.
         return proceed();
      }
   }
   else {
      // It's an interceptor, so we just invoke it: The pointcut will have
      // been evaluated statically before this object was constructed.
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

上面的代码可以分成三块来看

第一块

这个地方的代码就是目标对象的实际执行的地方,也就是c.sayHello()的实际执行的调用的地方

第二块

这一块是一个递归调用

第三块

这一块就是我们的@before、@around、@after等注解注释的方法的执行调用的地方,这里@before、@around、@after等注解的方法都会被封装到不同的MethodInterceptor子类对象中去,也就是说MethodInterceptor子类对象里面会记录这些注解对应的方法的元数据信息,当调用MethodInterceptor#invoke的时候会根据这些元数据信息通过反射的方式调用实际对应的方法,也就是我们上面创建的MyAspect这个类的before()、after()这些方法。

总结:Spring AOP的底层简单来讲就是看bean容器里面有没有@Aspect标注的bean,如果有则看它的PointCut对应的规则,只要在创建bean的时候符合这个PointCut规则的,就用CBLib动态代理的方式创建代理对象作为bean放到容器中,当我们从bean容器中获取代理对象bean并调用它的方法的时候,因为这个bean是通过代理的方式创建的,所以必然会走org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept()方法,而这个方法也必然会执行org.springframework.aop.framework.ReflectiveMethodInvocation#proceed()这个方法,而这个方法就会根据上面说的执行过程依次执行不同的MethodInterceptor子类对象的invoke()方法,这个方法会根据元数据信息通过反射的方式调用代理对象对应的真正的对象的方法,例如我上面创建的MyAspect这个类的before()、after()这些方法。

 

Spring AOP (Aspect Oriented Programming) 是 Spring 框架中的一个模块,它实现了面向切面编程,允许开发者将横切关注点(如事务管理、日志记录、安全检查等)抽取到独立的模块中,从而避免代码重复和提高模块的可维护性。Spring AOP底层原理主要基于以下几个关键概念: 1. **通知(Advice)**: 是 AOP 的核心,它是对目标方法执行前后的行为进行增强的代码片段。Spring 提供了五种类型的通知:前置通知(Before)、后置通知(After)、返回后通知(AfterReturning)、异常通知(AfterThrowing)和最终通知(Around)。 2. **切点(Pointcut)**: 定义了一组相关的通知应该何时何地应用。Spring 使用表达式语言(如`@annotation`, `@execution`, `@target`, `@within`等)来定义切点,匹配方法执行的条件。 3. **连接点(Join Point)**: 是程序执行过程中的一点,是通知被应用的地方。Spring AOP 检查通知的匹配条件并在合适的时候执行。 4. **代理(AOP Proxy)**: Spring AOP 实现了一种特殊的代理机制,为被拦截的目标对象创建一个代理对象。有两种代理模式:JDK 动态代理和 CGLIB 生成的字节码代理。对于接口,使用 JDK 动态代理;对于类,如果目标类没有实现接口或没有 final 方法,使用 CGLIB。 5. **切面(Angle)**: 是一组相关通知的集合,由切点和通知组成。在 Spring 中,切面通过 `@Aspect` 注解声明,`@AspectJ` 是其底层语法支持。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值