Spring源码 - Spring AOP底层逻辑详解(万字长文)

引言

这篇文章,我们讲讲 Spring 的核心机制 AOP(Aspect-Oriented Programming,面向切面编程)是如何实现的?这种编程范式的核心思想,无论你是用哪种语言开发,一定对你有所帮助。

Spring AOP 官方解释

在 Spring 官网中有对 Spring AOP 的解释:

在这里插入图片描述

全文的意思是:

面向切面编程(AOP)通过提供另一种程序结构的思维方式,对面向对象编程(OOP)进行了补充。在 OOP 中,模块化的核心单元是,而在 AOP 中,模块化的核心单元是切面。切面能够将那些横跨多个类型和对象的关注点(例如事务管理)进行模块化封装。(此类关注点在 AOP 领域常被称为**“横切关注点”**)。

Spring 框架的核心组件之一是 AOP 框架。尽管 Spring 的 IoC 容器并不依赖于 AOP(即您可以不启用 AOP 功能),但 AOP 与 Spring IoC 的结合,共同提供了一个功能强大的中间件解决方案。

在 Spring 框架中,AOP 主要用于以下场景:

  1. 提供声明式企业服务:其中最重要的服务是声明式事务管理(例如通过 @Transactional 注解实现)。
  2. 支持用户自定义切面:允许开发者通过 AOP 扩展 OOP 的能力,将业务逻辑与横切关注点解耦。

源码解析

调试用例

假如我们有这么一个Aspect(切面):

@Aspect
@Component
public class LogAspect {

	@After("execution(* org.springframework.boot.launchscript.controller.*.*(..))")
	public void logAfter(JoinPoint joinPoint) {
		System.out.println("After method: " + joinPoint.getSignature());
	}

	@Before("execution(* org.springframework.boot.launchscript.controller.Laun*.*(..))")
	public void logBefore(JoinPoint joinPoint) {
		System.out.println("Before method: " + joinPoint.getSignature());
	}
}

@RestController
public class LaunchVerificationController {

	@RequestMapping("/testJdkProxy")
	public String testJdkProxy() {
		userService.createUser("testJdkProxy");
		System.out.println("是否为JDK代理: " + AopUtils.isJdkDynamicProxy(userService));
		System.out.println("是否为CGLIB代理: " + AopUtils.isCglibProxy(userService));
		return "testJdkProxy done";
	}
}
创建AOP代理对象的过程
applyBeanPostProcessorsAfterInitialization 初始化后置处理

Spring Boot 启动后,我们在 createBean 的 初始化阶段,也就是 initializeBean 方法中,在 invokeInitMethods 执行完初始化后,执行 applyBeanPostProcessorsAfterInitialization,内部是遍历 BeanPostProcessor 进行责任链式的处理

在这里插入图片描述

在这里插入图片描述

其中,其中一个 BeanPostProcessor 实现类 AbstractAutoProxyCreator 执行了postProcessAfterInitialization,这里就是代理的执行入口。

AbstractAutoProxyCreator#wrapIfNecessary 如需要就包装

在这里插入图片描述

AbstractAutoProxyCreator#postProcessAfterInitialization 执行了 AbstractAutoProxyCreator#wrapIfNecessary 方法。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { // 1. 检查是否为手动指定的 TargetSource Bean(例如通过 @Bean 自定义 TargetSource)
       return bean; // 已自定义 TargetSource,无需代理
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { // 2. 检查缓存是否已标记该 Bean 不需要代理
       return bean; // 直接返回原始 Bean
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { // 3. 排除基础设施类(如 Advice/Advisor 等)和应跳过的类(如切面类自身)
       this.advisedBeans.put(cacheKey, Boolean.FALSE); // 标记为不代理
       return bean;
    }
    /// 4. 核心逻辑:获取适用于该 Bean 的增强(Advice)和切面(Advisor)
    // Create proxy if we have advice.
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) { // 5. 判断是否需要创建代理 // 存在适用的增强逻辑
       this.advisedBeans.put(cacheKey, Boolean.TRUE); // 标记为已代理
       Object proxy = createProxy( // 6. 创建代理对象(JDK 或 CGLIB)
             bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // 封装原始 Bean 为 TargetSource
       this.proxyTypes.put(cacheKey, proxy.getClass()); // 记录代理类型
       return proxy; // 返回代理对象
    }
    // 7. 无增强逻辑,标记为不代理
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

AbstractAutoProxyCreator#wrapIfNecessary 最重要的两个步骤

  1. 用 getAdvicesAndAdvisorsForBean 获取 我们定义的Aspect的拦截器数组 specificInterceptors,这里底层是通过匹配表达式来做的。
  2. 调用 AbstractAutoProxyCreator#createProxy 去创建代理对象 proxy,最终获取到的 obj 对象为 LaunchVerificationController$$EnhancerBySpringCGLIB$$c16af234@6495

CGLIB 代理对象的命名规则:

  • LaunchVerificationController:原始目标类的类名。
  • $$EnhancerBySpringCGLIB$$:Spring 使用 CGLIB 生成代理类的固定前缀。
  • c16af234:CGLIB 生成的唯一标识符(十六进制哈希值)。
  • @6495:代理对象实例的内存地址哈希码(Object.toString() 默认输出)。

在这里插入图片描述

从截图的表达式可以看出,我们从 getAdvicesAndAdvisorsForBean 获取了我们写的 @Aspect 的拦截器 pointcut(切入点)。

AbstractAutoProxyCreator#createProxy 创建代理

接下来就是创建代理:AbstractAutoProxyCreator#createProxy

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
       @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    // 1. 暴露目标类的 Class 到 BeanFactory(用于其他后处理器识别原始类型)
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
       AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }
    // 2. 创建代理工厂并继承全局配置(如 proxyTargetClass、exposeProxy 等)
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this); // 从当前 AutoProxyCreator 继承配置
    // 3. 确定代理类型(JDK 动态代理 或 CGLIB)
    if (!proxyFactory.isProxyTargetClass()) {
       if (shouldProxyTargetClass(beanClass, beanName)) { // 根据条件判断是否强制使用 CGLIB 代理
          proxyFactory.setProxyTargetClass(true); // 启用 CGLIB
       }
       else {
          evaluateProxyInterfaces(beanClass, proxyFactory); // 检查 Bean 是否有接口,决定是否使用 JDK 动态代理
       }
    }
    // 4. 构建 Advisor 链(将拦截器转换为 Spring AOP 的 Advisor 对象)
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource); // 5. 设置目标源(原始 Bean 的包装)
    customizeProxyFactory(proxyFactory); // 6. 允许子类自定义 ProxyFactory(扩展点)

    proxyFactory.setFrozen(this.freezeProxy); // 7. 冻结配置(代理生成后禁止修改,提升性能)
    if (advisorsPreFiltered()) { // 8. 标记 Advisors 是否已预过滤(优化拦截器执行)
       proxyFactory.setPreFiltered(true);
    }
    /// 9. 生成代理对象(根据 proxyTargetClass 选择 JDK/CGLIB)
    return proxyFactory.getProxy(getProxyClassLoader());
}

步骤拆解:

  1. buildAdvisors 构建 Advisor 链(将拦截器转换为 Spring AOP 的 Advisor 对象)
  2. proxyFactory.getProxy 生成代理对象(根据 proxyTargetClass 选择 JDK/CGLIB)

buildAdvisors 是做了转换,先不深入,主要看 proxyFactory.getProxy(ProxyFactory#getProxy)

public Object getProxy(@Nullable ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader); // 创建一个 AOP 代理对象,并通过指定的类加载器获取代理实例
}

getProxy 分为了两步,createAopProxy 创建AOP代理 -> getProxy 获取AOP代理

DefaultAopProxyFactory#createAopProxy 进行 CGLIB/JDK 的选择

createAopProxy 走到了这里,去执行动态代理方案 CGLIB/JDK 的选择:

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { // 条件1: 优化模式开启 | 强制代理目标类 | 无用户指定接口 → 倾向使用 CGLIB
       Class<?> targetClass = config.getTargetClass();
       if (targetClass == null) {
          throw new AopConfigException("TargetSource cannot determine target class: " +
                "Either an interface or a target is required for proxy creation.");// 无法确定目标类:创建代理需要至少一个接口或具体目标类
       }
       if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { // 条件2: 目标类本身是接口 或 已为 JDK 代理类 → 回退 JDK 代理
          return new JdkDynamicAopProxy(config); /// JDK 动态代理
       }
       return new ObjenesisCglibAopProxy(config); /// 否则使用 CGLIB(优先 Objenesis 绕过构造器优化)
    }
    else {
       return new JdkDynamicAopProxy(config); /// 默认使用 JDK 动态代理(需存在接口)
    }
}

我们的用例则是获取到了 ObjenesisCglibAopProxy,可以看出是要执行 Cglib 代理

createAopProxy 创建了AOP代理,接下来就是去getProxy获取代理 ,CglibAopProxy#getProxy 逻辑,核心就是通过配置 Enhancer 去创建代理对象,最终 enhancer.create 去创建代理对象。

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isTraceEnabled()) {
       logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
    }

    try {
       Class<?> rootClass = this.advised.getTargetClass(); // 1. 获取目标类并校验
       Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
       // 2. 处理 CGLIB 多层代理场景
       Class<?> proxySuperClass = rootClass;
       if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) { // 判断是否已是 CGLIB 代理类
          proxySuperClass = rootClass.getSuperclass(); // 如果是 CGLIB 代理类,取其父类作为代理基类
          Class<?>[] additionalInterfaces = rootClass.getInterfaces(); // 将原代理类的接口继承到新代理配置中
          for (Class<?> additionalInterface : additionalInterfaces) {
             this.advised.addInterface(additionalInterface);
          }
       }

       // Validate the class, writing log messages as necessary.
       validateClassIfNecessary(proxySuperClass, classLoader); // 3. 类合法性校验(如 final 修饰符检查)

       // Configure CGLIB Enhancer...
       Enhancer enhancer = createEnhancer(); // 4. 配置 CGLIB Enhancer(核心代理生成器)
       if (classLoader != null) {
          enhancer.setClassLoader(classLoader); // 4.1 设置类加载器
          if (classLoader instanceof SmartClassLoader &&
                ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
             enhancer.setUseCache(false); // 动态类加载器优化:禁用缓存确保热加载生效
          }
       }
       enhancer.setSuperclass(proxySuperClass); // 4.2 设置父类(代理类将继承此类)
       enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); // 4.3 设置代理接口(合并用户指定的接口和 SpringProxy 标记接口)
       enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); // 4.4 命名策略(生成类似 UserService$$EnhancerBySpringCGLIB$$12345a 的类名)
       enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader)); // 4.5 生成策略(处理类加载器上下文)

       Callback[] callbacks = getCallbacks(rootClass); // 5. 创建回调链(包含拦截器、目标方法调用等)
       Class<?>[] types = new Class<?>[callbacks.length];
       for (int x = 0; x < types.length; x++) {
          types[x] = callbacks[x].getClass(); // 5.1 获取回调类型数组(用于后续CallbackFilter匹配)
       }
       // fixedInterceptorMap only populated at this point, after getCallbacks call above
       enhancer.setCallbackFilter(new ProxyCallbackFilter( // 6. 设置回调过滤器(决定不同方法使用哪个Callback)
             this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
       enhancer.setCallbackTypes(types);

       // Generate the proxy class and create a proxy instance.
       return createProxyClassAndInstance(enhancer, callbacks); /// 7. 生成代理类并创建实例(核心生成逻辑)
    }
    catch (CodeGenerationException | IllegalArgumentException ex) {
       throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
             ": Common causes of this problem include using a final class or a non-visible class",
             ex); // 典型异常:目标类是 final 类或非可见类
    }
    catch (Throwable ex) {
       // TargetSource.getTarget() failed
       throw new AopConfigException("Unexpected AOP exception", ex); // 其他未知异常(如目标对象获取失败)
    }
}

进入到 ObjenesisCglibAopProxy#createProxyClassAndInstance

@Override
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
    Class<?> proxyClass = enhancer.createClass(); // 1. 生成代理类字节码并加载到JVM
    Object proxyInstance = null;
    // 2. 优先尝试通过Objenesis库创建实例(绕过构造器)
    if (objenesis.isWorthTrying()) { // 检查是否值得尝试(根据黑名单/白名单配置)
       try { // 2.1 Objenesis的newInstance方法不需要调用构造器
          proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
       }
       catch (Throwable ex) { // 2.2 Objenesis创建失败时记录日志(非致命错误,可回退)
          logger.debug("Unable to instantiate proxy using Objenesis, " +
                "falling back to regular proxy construction", ex); // 无法通过Objenesis实例化代理,将回退到常规构造方法创建
       }
    }
    // 3. Objenesis创建失败时的备选方案:反射调用默认构造器
    if (proxyInstance == null) {
       // Regular instantiation via default constructor...
       try { // 3.1 根据是否预定义构造器参数选择构造器
          Constructor<?> ctor = (this.constructorArgs != null ?
                proxyClass.getDeclaredConstructor(this.constructorArgTypes) :
                proxyClass.getDeclaredConstructor());
          ReflectionUtils.makeAccessible(ctor); // 3.2 确保私有构造器可访问
          proxyInstance = (this.constructorArgs != null ?
                ctor.newInstance(this.constructorArgs) : ctor.newInstance()); // 3.3 通过反射创建实例
       }
       catch (Throwable ex) { // 3.4 反射创建失败时抛出致命异常
          throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
                "and regular proxy instantiation via default constructor fails as well", ex); // Objenesis和常规构造器实例化均失败
       }
    }
    // 4. 将回调链设置到代理实例(CGLIB的Factory接口方法)
    ((Factory) proxyInstance).setCallbacks(callbacks);
    return proxyInstance;
}
CGLIB 下 Enhancer 创建代理

在这里插入图片描述

这里 Enhancer 创建动态代理的逻辑可以简化为:(仅供参考)

// 生成CGLIB代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Xxx.class); // 继承方式代理
Class<?> proxyClass = enhancer.createClass(); // 生成代理类字节码并加载到JVM
Object proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache()); // 绕过构造函数创建对象实例
((Factory) proxyInstance).setCallbacks(new Callbacks[]{(MethodInterceptor) (obj, method, args, proxy) -> {
		// AOP 逻辑在这里..
    return proxy.invokeSuper(obj, args);
}}); // 设置回调
return proxyInstance; // 最终代理对象

我们创建的对象就会返回CGLIB代理过的对象,这个代理对象取代了原先的 Bean,存在于IOC容器中。TODO CGLIB 底层原理我们暂且不深入探究,留个坑~

补充:getAdvicesAndAdvisorsForBean 扫描匹配的 Aspect

我们刚刚还有一个点没讲到,getAdvicesAndAdvisorsForBean 是如何匹配表达式的呢?

我持续深入debug,这里给出执行栈:

org.aspectj.weaver.patterns.SignaturePattern.matchesExactlyMethod(SignaturePattern.java:471)
	  at org.aspectj.weaver.patterns.SignaturePattern.matchesExactly(SignaturePattern.java:363)
	  at org.aspectj.weaver.patterns.SignaturePattern.matches(SignaturePattern.java:323)
	  at org.aspectj.weaver.patterns.KindedPointcut.matchInternal(KindedPointcut.java:202)
	  at org.aspectj.weaver.patterns.Pointcut.match(Pointcut.java:137)
	  at org.aspectj.weaver.internal.tools.PointcutExpressionImpl.getShadowMatch(PointcutExpressionImpl.java:319)
	  at org.aspectj.weaver.internal.tools.PointcutExpressionImpl.matchesExecution(PointcutExpressionImpl.java:129)
	  at org.aspectj.weaver.internal.tools.PointcutExpressionImpl.matchesMethodExecution(PointcutExpressionImpl.java:110)
	  at org.springframework.aop.aspectj.AspectJExpressionPointcut.getShadowMatch(AspectJExpressionPointcut.java:462)
	  - locked <0xffa> (a java.util.concurrent.ConcurrentHashMap)
	  at org.springframework.aop.aspectj.AspectJExpressionPointcut.getTargetShadowMatch(AspectJExpressionPointcut.java:447)
	  at org.springframework.aop.aspectj.AspectJExpressionPointcut.matches(AspectJExpressionPointcut.java:295)
	  at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:251)
	  at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:289)
	  at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:321)
	  at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:128)
	  at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:97)
	  at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:78)
	  at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:347)
	  at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:299)
	  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:430)
	  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1798)
	  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594)
	  at 

匹配方法:

org.aspectj.weaver.patterns.SignaturePattern#matchesExactlyMethod

/**
 * 精确匹配方法签名是否符合切点表达式
 * 
 * @param aMethod      待匹配的方法签名
 * @param world        类型解析上下文(用于处理泛型等)
 * @param subjectMatch 是否校验异常声明(当切点包含throws时启用)
 * @return FuzzyBoolean 匹配结果(YES-匹配 / NO-不匹配 / MAYBE-可能匹配)
 */
private FuzzyBoolean matchesExactlyMethod(JoinPointSignature aMethod, World world, boolean subjectMatch) {
    // 1. 快速失败:参数数量或类型明显不匹配
    if (this.parametersCannotMatch(aMethod)) {
        return FuzzyBoolean.NO; 
    }
    // 2. 方法名不匹配(如切点表达式指定了特定方法名)
    if (!this.name.matches(aMethod.getName())) {
        return FuzzyBoolean.NO;
    }
    // 3. 校验异常声明(当切点包含throws子句时)
    if (subjectMatch && !this.throwsPattern.matches(aMethod.getExceptions(), world)) {
        return FuzzyBoolean.NO;
    }
    // 4. 校验声明类(declaring type)
    if (!this.declaringType.isStar() && 
        !this.declaringType.matchesStatically(aMethod.getDeclaringType().resolve(world))) {
        return FuzzyBoolean.MAYBE; // 可能因泛型擦除导致不确定
    }
    
    // 5. 校验返回类型
    if (!this.returnType.isStar()) {
        boolean isBangVoid = this.returnType.isBangVoid(); // 匹配非void类型
        if (isBangVoid) {
            String returnSig = aMethod.getReturnType().getSignature();
            if (returnSig.length() == 1 && returnSig.charAt(0) == 'V') { // 'V'表示void
                return FuzzyBoolean.NO; // 返回void但需要非void → 不匹配
            }
        } else if (this.returnType.isVoid()) { // 匹配void返回类型
            String returnSig = aMethod.getReturnType().getSignature();
            if (returnSig.length() != 1 || returnSig.charAt(0) != 'V') {
                return FuzzyBoolean.NO; // 非void返回 → 不匹配
            }
        } else if (!this.returnType.matchesStatically(aMethod.getReturnType().resolve(world)) && 
                   !this.returnType.matchesStatically(aMethod.getGenericReturnType().resolve(world))) {
            return FuzzyBoolean.MAYBE; // 泛型类型可能擦除导致不确定
        }
    }
    
    // 6. 处理可变参数(如切点表达式中的...)
    if (this.parameterTypes.size() == 1 && this.parameterTypes.get(0).isEllipsis()) {
        return FuzzyBoolean.YES; // 可变参数直接匹配
    }
    // 7. 参数数量不匹配
    if (!this.parameterTypes.canMatchSignatureWithNParameters(aMethod.getParameterTypes().length)) {
        return FuzzyBoolean.NO;
    }
    
    // 8. 参数类型匹配
    ResolvableTypeList rtl = new ResolvableTypeList(world, aMethod.getParameterTypes());
    ResolvedType[][] paramAnnotations = null;
    // 9. 校验参数注解(当切点包含参数注解匹配时)
    if (this.isMatchingParameterAnnotations()) {
        paramAnnotations = aMethod.getParameterAnnotationTypes();
        if (paramAnnotations != null && paramAnnotations.length == 0) {
            paramAnnotations = null; // 无注解时忽略
        }
    }
    // 10. 参数类型或注解不匹配
    if (!this.parameterTypes.matches(rtl, TypePattern.STATIC, paramAnnotations).alwaysTrue() &&
        !this.parameterTypes.matches(new ResolvableTypeList(world, aMethod.getGenericParameterTypes()), 
                                    TypePattern.STATIC, paramAnnotations).alwaysTrue()) {
        return FuzzyBoolean.MAYBE; // 泛型导致可能匹配
    }
    // 11. 可变参数特殊处理(如匹配最后一个参数是数组)
    if (!this.matchesVarArgs(aMethod, world)) {
        return FuzzyBoolean.MAYBE;
    }
    
    // 12. 所有条件满足 → 完全匹配
    return FuzzyBoolean.YES;
}

其实就是一直匹配下去,全部true才是匹配成功。

以小见大 —— 类名匹配算法

匹配逻辑有点多,我们只看类名匹配逻辑, this.declaringType.matchesStatically 走下去,直到 org.aspectj.weaver.patterns.WildTypePattern#innerMatchesExactly 这段逻辑。

/**
 * 精确匹配输入字符串是否符合预定义的分段模式规则
 * 
 * @param s 待匹配的原始字符串(例如类全限定名)
 * @param isAnonymous 是否处理匿名类(影响结尾模式校验)
 * @param convertDollar 是否将$视为分隔符(用于处理内部类)
 * @return 是否完全匹配模式规则
 */
private boolean innerMatchesExactly(String s, boolean isAnonymous, boolean convertDollar) {
    List<char[]> ret = new ArrayList(); // 存储分割后的字符串段
    int startIndex = 0; // 当前处理段的起始位置

    // 循环分割字符串(按.或$分隔)
    while(true) {
        // 查找下一个分隔符位置(优先.,convertDollar为true时考虑$)
        int breakIndex = s.indexOf('.', startIndex);
        if (convertDollar && breakIndex == -1) {
            breakIndex = s.indexOf('$', startIndex); // 处理内部类分隔符
        }

        // 处理最后一段字符串
        if (breakIndex == -1) {
            // 添加最后一段字符数组
            ret.add(s.substring(startIndex).toCharArray());
            int segmentCount = ret.size(); // 总段数
            int patternsLength = this.namePatterns.length; // 模式规则数量

            // --- 规则校验阶段 ---
            // 规则1:匿名类要求最后一个模式必须是通配符(如com.example..*)
            if (!this.namePatterns[patternsLength - 1].isAny() && isAnonymous) {
                return false;
            }

            // 场景1:无省略号模式(要求严格分段匹配)
            if (this.ellipsisCount == 0) {
                // 段数必须与模式数量严格一致
                if (segmentCount != patternsLength) return false;
                // 逐段匹配模式
                for (int i=0; i<patternsLength; i++) {
                    if (!this.namePatterns[i].matches(ret.get(i))) {
                        return false;
                    }
                }
                return true; // 全匹配
            }

            // 场景2:单省略号模式(允许中间段数可变)
            if (this.ellipsisCount == 1) {
                // 最少需要满足 patternsLength-1 段(省略号占一个模式位)
                if (segmentCount < patternsLength - 1) return false;
                int matchIndex = 0; // 当前匹配段索引
                for (int patternIndex=0; patternIndex<patternsLength; patternIndex++) {
                    NamePattern pattern = this.namePatterns[patternIndex];
                    if (pattern == NamePattern.ELLIPSIS) { // 遇到省略号模式
                        // 跳过后面的段,直到剩余模式能匹配剩余段
                        matchIndex = segmentCount - (patternsLength - patternIndex - 1);
                    } else if (!pattern.matches(ret.get(matchIndex++))) {
                        return false;
                    }
                }
                return true;
            }

            // 场景3:多个省略号模式(递归处理复杂匹配)
            return outOfStar(
                this.namePatterns, 
                ret.toArray(new char[0][]), // 转换成分段数组
                0, // 当前模式索引
                0, // 当前段索引
                patternsLength - this.ellipsisCount, // 非省略号模式数
                segmentCount, // 总段数
                this.ellipsisCount // 省略号数量
            );
        }

        // 截取当前段并存储
        char[] segment = s.substring(startIndex, breakIndex).toCharArray();
        ret.add(segment);
        startIndex = breakIndex + 1; // 跳过分隔符继续处理
    }
}

这个就是表达式匹配逻辑,是用分段匹配的方式进行,用“点”进行分割为数组,然后逐个匹配,我们的 namePatterns 如下:

在这里插入图片描述

我们的表达式是:org.springframework.boot.launchscript.controller.Laun*,被拆成了6段,然后等待被逐一匹配。

我们的待匹配类是:org.springframework.boot.launchscript.controller.LaunchVerificationController,被循环根据“点”号拆成了6段,然后依次加入到 ret 数组中。下一次循环,由于"点"号再也取不到, breakIndex = s.indexOf(46, startIndex) ,breakIndex 是 -1,所以进入最终匹配逻辑。

我们由于没有省略号 ellipsisCount == 0,所以进入以下循环:

while(patternsIndex < patternsLength) {
    if (!this.namePatterns[patternsIndex++].matches((char[])ret.get(namesIndex++))) {
        return false;
    }
}

匹配的方法 org.aspectj.weaver.patterns.NamePattern#matches(char[]) 也是 aspectj 提供的匹配逻辑。

在这里插入图片描述

这里的匹配逻辑,就是一个算法:匹配有“星号”的字符串。

到这里,我们就知道了,我们提供的 Aspect 的表达式是如何被 match/canApply 的了。

被代理对象长什么样?
拓展:MVC 请求链路

我们知道代理Bean是如何被创建的,那么,代理完成的 Bean到底长什么样呢?

我们第一次 HTTP 请求,会有很多懒加载的 MVC 相关的 Bean 创建,走了代理流程,我们先不管,直接进入第二次请求。

在这里插入图片描述

执行栈为:

logBefore:17, LogAspect (org.springframework.boot.launchscript.aop)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeAdviceMethodWithGivenArgs:644, AbstractAspectJAdvice (org.springframework.aop.aspectj)
invokeAdviceMethod:626, AbstractAspectJAdvice (org.springframework.aop.aspectj)
before:44, AspectJMethodBeforeAdvice (org.springframework.aop.aspectj)
invoke:55, MethodBeforeAdviceInterceptor (org.springframework.aop.framework.adapter)
proceed:186, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:749, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
invoke:95, ExposeInvocationInterceptor (org.springframework.aop.interceptor)
proceed:186, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:749, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
intercept:691, CglibAopProxy$DynamicAdvisedInterceptor (org.springframework.aop.framework)
testJdkProxy:-1, LaunchVerificationController$$EnhancerBySpringCGLIB$$59a6f870 (org.springframework.boot.launchscript.controller)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
doInvoke:190, InvocableHandlerMethod (org.springframework.web.method.support)
invokeForRequest:138, InvocableHandlerMethod (org.springframework.web.method.support)
invokeAndHandle:105, ServletInvocableHandlerMethod (org.springframework.web.servlet.mvc.method.annotation)
invokeHandlerMethod:878, RequestMappingHandlerAdapter (org.springframework.web.servlet.mvc.method.annotation)
handleInternal:792, RequestMappingHandlerAdapter (org.springframework.web.servlet.mvc.method.annotation)
handle:87, AbstractHandlerMethodAdapter (org.springframework.web.servlet.mvc.method)
doDispatch:1040, DispatcherServlet (org.springframework.web.servlet)
doService:943, DispatcherServlet (org.springframework.web.servlet)
processRequest:1006, FrameworkServlet (org.springframework.web.servlet)
doGet:898, FrameworkServlet (org.springframework.web.servlet)
service:497, HttpServlet (javax.servlet.http)
service:883, FrameworkServlet (org.springframework.web.servlet)
service:584, HttpServlet (javax.servlet.http)
handleRequest:74, ServletHandler (io.undertow.servlet.handlers)
doFilter:129, FilterHandler$FilterChainImpl (io.undertow.servlet.handlers)
doFilterInternal:100, RequestContextFilter (org.springframework.web.filter)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
doFilter:61, ManagedFilter (io.undertow.servlet.core)
doFilter:131, FilterHandler$FilterChainImpl (io.undertow.servlet.handlers)
doFilterInternal:93, FormContentFilter (org.springframework.web.filter)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
doFilter:61, ManagedFilter (io.undertow.servlet.core)
doFilter:131, FilterHandler$FilterChainImpl (io.undertow.servlet.handlers)
doFilterInternal:201, CharacterEncodingFilter (org.springframework.web.filter)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
doFilter:61, ManagedFilter (io.undertow.servlet.core)
doFilter:131, FilterHandler$FilterChainImpl (io.undertow.servlet.handlers)
handleRequest:84, FilterHandler (io.undertow.servlet.handlers)
handleRequest:62, ServletSecurityRoleHandler (io.undertow.servlet.handlers.security)
handleRequest:68, ServletChain$1 (io.undertow.servlet.handlers)
handleRequest:36, ServletDispatchingHandler (io.undertow.servlet.handlers)
handleRequest:68, RedirectDirHandler (io.undertow.servlet.handlers)
handleRequest:111, SSLInformationAssociationHandler (io.undertow.servlet.handlers.security)
handleRequest:57, ServletAuthenticationCallHandler (io.undertow.servlet.handlers.security)
handleRequest:43, PredicateHandler (io.undertow.server.handlers)
handleRequest:46, AbstractConfidentialityHandler (io.undertow.security.handlers)
handleRequest:64, ServletConfidentialityConstraintHandler (io.undertow.servlet.handlers.security)
handleRequest:60, AuthenticationMechanismsHandler (io.undertow.security.handlers)
handleRequest:77, CachedAuthenticatedSessionHandler (io.undertow.servlet.handlers.security)
handleRequest:43, AbstractSecurityContextAssociationHandler (io.undertow.security.handlers)
handleRequest:43, PredicateHandler (io.undertow.server.handlers)
handleRequest:43, PredicateHandler (io.undertow.server.handlers)
handleFirstRequest:269, ServletInitialHandler (io.undertow.servlet.handlers)
access$100:78, ServletInitialHandler (io.undertow.servlet.handlers)
call:133, ServletInitialHandler$2 (io.undertow.servlet.handlers)
call:130, ServletInitialHandler$2 (io.undertow.servlet.handlers)
call:48, ServletRequestContextThreadSetupAction$1 (io.undertow.servlet.core)
call:43, ContextClassLoaderSetupAction$1 (io.undertow.servlet.core)
dispatchRequest:249, ServletInitialHandler (io.undertow.servlet.handlers)
access$000:78, ServletInitialHandler (io.undertow.servlet.handlers)
handleRequest:99, ServletInitialHandler$1 (io.undertow.servlet.handlers)
executeRootHandler:376, Connectors (io.undertow.server)
run:830, HttpServerExchange$1 (io.undertow.server)
runWorker:1149, ThreadPoolExecutor (java.util.concurrent)
run:624, ThreadPoolExecutor$Worker (java.util.concurrent)
run:750, Thread (java.lang)

在这里插入图片描述

请求先通过 undertow worker 线程,用 Connectors 处理 IO流,用 HttpServerExchange 封装请求进行流转,到经典的 DispatcherServlet#doDispatch,分发,其中 mappedHandler = this.getHandler(processedRequest); 就是拿到我们的处理器,也就是我们被代理的控制器的方法。其中,我们是从 requestMappingHandlerMapping 的 mappingRegistry 中通过 请求 url ,从 mappingLookup (url 和 beanName 、method 的映射情况 Map)拿到的匹配情况,然后后续再拿到 handler(HandlerMethod)。这时我们拿到的还只是 bean 名称。

在这里插入图片描述

在这里插入图片描述

那我们要看看如何拿到代理对象的?是后面通过 handlerMethod.createWithResolvedBean() ,直接从 beanFactory 也就是 IOC 容器中,根据名称获取 bean,当然我们这个流程已经是在 Spring Boot 启动后了,所以直接从 singletonObjects 一级缓存中获取。

在这里插入图片描述

我们逻辑往外走,后续是通过 InvocableHandlerMethod#doInvoke 桥接 Method 进行反射调用 bean(被代理的) 的mvc方法。

在这里插入图片描述

我们可以通过堆栈分析,执行到了 testJdkProxy:-1,也就是说这部分是动态生成的没有对应的源代码文件(字节码生成 class),这部分是没有源代码的,也就是说字节码是一个动态的东西,源码无法体现。我们看下字节码长什么样。

-Dcglib.debugLocation=./.cglib
-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true

VM 参数加上这两个,就可以运行后看到cglib字节码。

在这里插入图片描述

我们看到的都是 IDEA 反编译后的,cglib 将 MethodInterceptor 织入到了逻辑里。

那我们继续往下调试,发现又到了有源代码的 DynamicAdvisedInterceptor#intercept,从这里我们可以看出,cglib 的代码是通过将拦截器的逻辑“织入”到字节码,然后在执行这个代理对象的被代理的方法的时候,调试时就会先走到“织入”的“盲区”,也就是字节码区,然后再回到程序的代码中来。来到 DynamicAdvisedInterceptor#intercept 进行处理。

在这里插入图片描述

DynamicAdvisedInterceptor#intercept 执行步骤如图:

在这里插入图片描述

拓展:不同的动态代理方案的对比

各种代理方式的对比:(网上提供的资料,真实性有待考究,仅供参考)

实现方式原理优点缺点
JDK 动态代理基于接口生成代理类($Proxy0无额外依赖,标准 JVM 支持要求目标类必须实现接口
CGLIB 字节码增强通过继承目标类生成子类(UserService$$EnhancerBySpringCGLIB$$...支持代理无接口的类无法代理 final 类/方法
AspectJ 织入编译时或类加载时直接修改字节码性能高,支持更细粒度的切点(如构造器、字段)需要额外编译器(如 AspectJ Maven 插件)

参考:

Spring技术内幕:深入解析Spring架构与设计原理(第2版)
Spring官方:https://docs.spring.io/spring-framework/reference/core/aop.html
Spring源码:https://github.com/spring-projects/spring-framework

关注公众号:【源码启示录】,解锁更多源码知识
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值