深入Spring AOP底层原理:从切面注册到代理生成

181 阅读33分钟

引言

Spring AOP(面向切面编程)是Spring框架的“灵魂”特性之一,它通过动态代理将横切关注点(如日志、事务、权限校验)与业务逻辑解耦。尽管开发者日常使用@Before@Around等注解轻松实现AOP,但其底层如何将切面逻辑织入目标对象、代理如何生成、切面如何匹配等核心机制仍充满技术细节。本文将基于Spring 5.3.x源码,结合字节码分析、反射调用链追踪,从切面注册→切点匹配→代理生成→通知执行全链路解析Spring AOP的底层原理。


一、切面注册:从代码到Spring容器的转化

1.1 编程式切面:手动构建Advisor链

用户提供的AdvisorAspectCase.LowerAspect通过@Bean方法手动注册了一个DefaultPointcutAdvisor,这是编程式切面的典型实现。我们以该代码为例,拆解切面注册的底层流程:

1.1.1 Advisor的创建流程

@Bean
public Advisor beforeAdviceAdvisor(MethodInterceptor interceptor) {
    // 步骤1:创建切点(AspectJExpressionPointcut)
    AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    pointcut.setExpression("execution(* com.dwl.advisor_aspect..*.foo())"); 
    
    // 步骤2:创建通知(MethodInterceptor实现的环绕通知)
    // 步骤3:绑定切点与通知,生成Advisor
    return new DefaultPointcutAdvisor(pointcut, interceptor);
}
  • AspectJExpressionPointcut的初始化
    当调用setExpression时,Spring会使用AspectJExpressionPointcut的内部类ExpressionParser(基于AspectJ的PointcutParser)解析切点表达式。例如,execution(* com.dwl.advisor_aspect..*.foo())会被解析为:

    • 类过滤器(ClassFilter)​​:匹配所有包路径下以com.dwl.advisor_aspect为根的类(..*表示任意子包和类)。
    • 方法匹配器(MethodMatcher)​​:匹配所有名为foo、任意参数的方法(*表示任意返回值,..表示任意参数)。
  • DefaultPointcutAdvisor的组装
    该类持有PointcutAdvice(此处是MethodInterceptor),是Spring AOP中“切点+通知”的最小执行单元。当后续代理生成时,Spring会将所有匹配的AdvisorAdvice按顺序编织到代理的拦截器链中。

1.1.2 通知的参数传递机制

debugInterceptor方法中,MethodInvocation参数提供了目标方法的上下文信息:

public Object invoke(MethodInvocation invocation) throws Throwable {
    Method method = invocation.getMethod();       // 目标方法
    Object[] args = invocation.getArguments();    // 目标方法参数
    Object target = invocation.getThis();         // 目标对象实例
    // ...
}
  • MethodInvocation的本质
    它是Spring AOP对目标方法调用的封装,内部通过MethodInvocationProceedingJoinPoint(继承自JoinPoint)实现AOP联盟标准接口。proceed()方法触发后续拦截器或目标方法的执行,形成拦截器链​(Interceptor Chain)。

1.2 注解式切面:从@Aspect类到Advisor的自动转换

AdvisorAspectCase.SeniorAspect通过@Aspect注解标记,Spring通过AnnotationAwareAspectJAutoProxyCreator自动将其转换为Advisor。这一过程涉及以下关键步骤:

1.2.1 切面类的扫描与解析

AnnotationAwareAspectJAutoProxyCreator在初始化时(postProcessBeanFactory方法)会扫描所有@Aspect注解的类,并通过AspectJAdvisorFactory(默认是ReflectiveAspectJAdvisorFactory)解析其中的通知方法。

1.2.2 通知方法的提取与Advisor生成

对于SeniorAspectbefore方法(标注@Before):

@Before("execution(* com.dwl.advisor_aspect..*.foo())")
public void before(JoinPoint joinPoint) { ... }
  • 切点表达式的解析​:
    @Beforevalue属性(或pointcut属性)会被解析为Pointcut对象。若表达式为空,则使用默认切点(匹配所有目标类方法)。
  • 通知类型的映射​:
    @Before对应MethodBeforeAdvice@After对应AfterAdvice@Around对应MethodInterceptor(最强大)。Spring会将这些通知适配为Advice接口的实现类(如MethodBeforeAdviceAdapter)。
  • Advisor的生成​:
    最终生成InstantiationModelAwarePointcutAdvisor,该类持有切点(Pointcut)和通知(Advice),并记录切面的实例化模型(如PER_THISPER_TARGET等,默认SINGLETON)。

二、切点匹配:findEligibleAdvisors的底层逻辑

2.1 核心方法:findEligibleAdvisors

AnnotationAwareAspectJAutoProxyCreator的核心方法是findEligibleAdvisors(继承自AbstractAdvisorAutoProxyCreator),其作用是筛选出适用于当前目标类的所有Advisor。我们通过反射调用该方法(如用户提供的FindEligibleAdvisorCase),观察其执行流程:

2.1.1 收集所有候选Advisor

首先,Spring会收集容器中所有Advisor类型的Bean(包括编程式注册的和注解式生成的),以及@Aspect切面类中提取的Advisor。

2.1.2 切点匹配:Pointcut的匹配逻辑

对于每个Advisor,Spring会调用其Pointcutmatches方法,判断是否适用于当前目标类(targetClass)和方法(method)。以AspectJExpressionPointcut为例,其matches方法的底层逻辑如下:

2.1.2.1 类过滤(ClassFilter)

ClassFilter判断目标类是否匹配切点的类表达式。例如,execution(* com.dwl.advisor_aspect..*.foo())的类表达式是com.dwl.advisor_aspect..*,对应的ClassFilter会检查目标类是否属于该包路径。

  • 实现类​:AspectJExpressionPointcut的类过滤器默认是TypePatternClassFilter,通过解析切点表达式中的类模式(如com.dwl.advisor_aspect..*)生成正则表达式,匹配目标类的全限定名。
2.1.2.2 方法匹配(MethodMatcher)

MethodMatcher判断目标方法是否匹配切点的方法表达式。例如,execution(* com.dwl.advisor_aspect..*.foo())的方法表达式是foo(),对应的MethodMatcher会检查目标方法的名称、参数类型、返回类型是否匹配。

  • 实现类​:AspectJExpressionPointcut的方法匹配器默认是MethodSignaturePatternMethodMatcher,通过解析切点表达式中的方法模式(如foo())生成方法签名匹配规则。
2.1.2.3 匹配结果的缓存

为了提升性能,AspectJExpressionPointcut会将匹配结果缓存到methodCacheConcurrentHashMap)中,键为(targetClass, method),值为匹配结果(boolean)。避免重复解析切点表达式。


三、代理生成:wrapIfNecessary的字节码级解析

3.1 代理生成的触发条件

wrapIfNecessary方法是Spring AOP生成代理的最终决策点,其核心逻辑如下(基于AbstractAutoProxyCreator源码):

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 1. 跳过已代理的对象(如循环依赖中的提前代理)
    if (bean instanceof AopInfrastructureBean || beanName.startsWith(AUTO_PROXY_CREATOR_BEAN_NAME_PREFIX)) {
        return bean;
    }

    // 2. 查找匹配的Advisor列表
    List<Advisor> eligibleAdvisors = findEligibleAdvisors(bean.getClass(), beanName);
    if (eligibleAdvisors.isEmpty()) {
        return bean; // 无匹配切面,返回原始对象
    }

    // 3. 生成代理对象
    return createProxy(bean.getClass(), beanName, eligibleAdvisors, cacheKey);
}

3.2 代理模式的选择:JDK vs CGLIB

Spring根据目标类是否实现接口选择代理模式:

  • JDK动态代理​:若目标类实现了至少一个接口,优先使用JDK动态代理(基于java.lang.reflect.Proxy)。
  • CGLIB代理​:若目标类未实现接口,或显式配置proxyTargetClass=true,则使用CGLIB(基于字节码增强)。

3.2.1 JDK动态代理的底层实现

JDK动态代理通过Proxy.newProxyInstance生成代理类,核心步骤如下:

  1. 生成代理类字节码​:
    JVM动态生成一个继承自Proxy的类(如com.dwl.advisor_aspect.ProxyCreationTimingBeanA$$Proxy),该类实现了目标类的所有接口。
  2. 实现InvocationHandler​:
    代理类的invoke方法会调用InvocationHandlerinvoke方法,后者负责执行切面逻辑(拦截器链)和目标方法。

示例代理类字节码(简化)​​:

public final class ProxyCreationTimingBeanA$$Proxy extends Proxy implements ProxyCreationTimingBeanA {
    private static Method m0; // Object.hashCode()
    private static Method m1; // Object.toString()
    private static Method m2; // ProxyCreationTimingBeanA.foo()
    private InvocationHandler h;

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 1. 执行前置通知(如编程式切面的环绕通知)
        // 2. 调用目标方法(通过h.invoke(target, method, args))
        // 3. 执行后置通知
        return h.invoke(this, method, args);
    }
}

3.2.2 CGLIB代理的底层实现

CGLIB通过Enhancer类生成目标类的子类,核心步骤如下:

  1. 生成子类字节码​:
    使用ASM库动态生成目标类的子类(如ProxyCreationTimingBeanA$$EnhancerBySpringCGLIB$$123456),重写目标方法。
  2. 方法拦截​:
    子类中重写的方法会调用MethodInterceptorintercept方法,后者负责执行切面逻辑和调用父类(目标类)的方法。

示例CGLIB子类字节码(简化)​​:

public class ProxyCreationTimingBeanA$$EnhancerBySpringCGLIB$$123456 extends ProxyCreationTimingBeanA {
    private MethodInterceptor interceptor;

    public void foo() {
        // 1. 执行前置通知
        interceptor.intercept(this, Method.forName("foo"), new Object[0], new MethodProxy(foo));
        // 2. 调用父类(原始对象)的foo()方法
        super.foo();
        // 3. 执行后置通知
    }
}

3.3 代理对象的增强:拦截器链的构建

无论JDK还是CGLIB代理,最终都需要将匹配的Advisor转换为拦截器链。Spring通过AdvisedSupport类管理拦截器链,核心逻辑如下:

// 伪代码:构建拦截器链
List<MethodInterceptor> interceptors = new ArrayList<>();
for (Advisor advisor : eligibleAdvisors) {
    Advice advice = advisor.getAdvice();
    if (advice instanceof MethodInterceptor) {
        interceptors.add((MethodInterceptor) advice);
    } else {
        // 将其他类型的Advice(如MethodBeforeAdvice)适配为MethodInterceptor
        interceptors.add(new MethodBeforeAdviceAdapter(advice));
    }
}
// 最终拦截器链:[环绕通知, @Before通知, @After通知, ...]

四、通知执行:拦截器链的调用流程

4.1 环绕通知的执行控制

@Around通知是最强大的通知类型,它通过ProceedingJoinPoint(继承自JoinPoint)控制目标方法的执行流程。以用户提供的AdvancedAspect.aroundSpecialMethod为例:

@Around("execution(* com.dwl.advisor_aspect..*.specialMethod())")
public Object aroundSpecialMethod(ProceedingJoinPoint joinPoint) throws Throwable {
    long start = System.currentTimeMillis();
    try {
        Object result = joinPoint.proceed(); // 调用目标方法(或下一个通知)
        log.info("耗时:{}ms,结果:{}", System.currentTimeMillis() - start, result);
        return result;
    } catch (Throwable e) {
        log.error("异常:{}", e.getMessage());
        throw e;
    }
}
  • proceed()的调用链
    joinPoint.proceed()会触发拦截器链中的下一个拦截器,直到到达目标方法。若所有拦截器都执行完毕,目标方法被调用,结果返回;若中途抛出异常,异常会被传递给后续的@AfterThrowing通知。

4.2 通知的执行顺序

Spring AOP的通知执行顺序由Advisor的注册顺序和切点匹配顺序决定。对于同一目标方法,典型的执行顺序如下(假设存在@Around@Before@AfterReturning三个通知):

1. @Around通知的前置逻辑(proceed()前)
2. @Before通知的前置逻辑
3. 目标方法执行
4. @AfterReturning通知的成功逻辑(目标方法正常返回)
5. @Around通知的后置逻辑(proceed()后,无异常)

4.3 异常处理机制

  • @AfterThrowing通知:当目标方法抛出异常时,Spring会跳过@AfterReturning通知,直接执行@AfterThrowing通知。
  • 异常传播:若@Around通知未捕获异常并重新抛出,异常会向上传播至调用方;若被捕获并处理,调用方将感知不到异常(除非显式重新抛出)。

五、循环依赖与代理的深度交互

5.1 循环依赖的解决机制

Spring通过三级缓存解决循环依赖:

  1. 一级缓存(singletonObjects)​​:存储已完全初始化的单例Bean。
  2. 二级缓存(earlySingletonObjects)​​:存储提前暴露的Bean引用(未完成初始化)。
  3. 三级缓存(singletonFactories)​​:存储Bean工厂(用于生成早期引用)。

5.2 代理在循环依赖中的行为

假设BeanA依赖BeanBBeanB依赖BeanA,且两者均被AOP代理:

  1. BeanA的初始化​:
    Spring创建BeanA的原始对象,发现其依赖BeanB,于是尝试注入BeanB
  2. BeanB的初始化​:
    Spring创建BeanB的原始对象,发现其依赖BeanA,于是尝试注入BeanA。此时BeanA尚未完成初始化,但三级缓存中已有BeanA的工厂(BeanFactory)。
  3. 提前暴露代理对象​:
    Spring通过singletonFactories获取BeanA的代理工厂,生成代理对象并注入BeanB。此时BeanB持有的BeanA是代理对象,而非原始对象。
  4. 完成初始化​:
    BeanABeanB最终完成初始化,代理对象在后续调用中拦截方法并执行切面逻辑。

5.3 关键验证:代理的提前生成

通过ProxyCreationTimingCase的日志可以看到,循环依赖中的Bean在@PostConstruct执行时已被代理:

[ProxyCreationTimingBeanC] 注入BeanD - 代理类型:class com.dwl.advisor_aspect.ProxyCreationTimingBeanD$$EnhancerBySpringCGLIB$$...

这说明Spring在循环依赖中提前生成了代理对象,确保依赖注入的是代理而非原始对象。


六、总结与扩展

6.1 总结

Spring AOP的底层原理可概括为以下核心步骤:

  1. 切面注册​:编程式切面通过DefaultPointcutAdvisor手动注册,注解式切面通过AnnotationAwareAspectJAutoProxyCreator自动转换为InstantiationModelAwarePointcutAdvisor
  2. 切点匹配​:AspectJExpressionPointcut解析切点表达式,通过类过滤和方法匹配判断Advisor是否适用于目标类。
  3. 代理生成​:wrapIfNecessary方法根据切点匹配结果,选择JDK或CGLIB生成代理对象,并构建拦截器链。
  4. 通知执行​:拦截器链按顺序执行通知逻辑(@Around@Before→目标方法→@AfterReturning/@AfterThrowing@After)。

6.2 扩展学习方向

  • 源码调试​:通过IDE调试AnnotationAwareAspectJAutoProxyCreatorpostProcessAfterInitialization方法,观察代理生成的完整调用链。
  • 性能优化​:分析CGLIB与JDK代理的性能差异(CGLIB在多次调用时更快,JDK代理更轻量)。
  • 自定义切面​:通过实现Advisor接口或继承AbstractPointcutAdvisor,自定义切面逻辑。
  • AspectJ集成​:了解Spring AOP与AspectJ的集成(如@EnableAspectJAutoProxy(proxyTargetClass = true)),掌握编译时织入(CTW)与运行时织入(RTW)的区别。

建议结合实际项目中的AOP使用场景(如事务管理、日志监控),进一步验证和扩展这些知识。

完整代码

package com.dwl.advisor_aspect;

import lombok.extern.slf4j.Slf4j;
import org.aopalliance.aop.Advice;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.*;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @ClassName AdvancedSectionChangeLowLevelSection
 * @Description 本类演示Spring AOP的5种核心通知方式(@Before/@After/@AfterReturning/@AfterThrowing/@Around)
 * * 结合编程式切面注册,覆盖通知方法的底层实现原理和典型使用场景
 * @Version 1.0.0
 * @Date 2025
 * @Author By Dwl
 */
@Slf4j
public class AdvancedSectionChangeLowLevelSection {


    public static void main(String[] args) {
        // 1. 创建切面实例工厂(单例模式,管理切面类的生命周期)
        AspectInstanceFactory aspectFactory = new SingletonAspectInstanceFactory(new AdvancedAspect());

        // 2. 动态解析切面类中的所有通知方法,生成Advisor列表
        List<Advisor> advisors = parseAspectMethods(aspectFactory);
        // 模拟Spring容器注册Advisor(实际开发中通过BeanPostProcessor自动完成)
        registerAdvisorsToContainer(advisors);

        // 3. 创建目标Bean
        AdvancedSectionChangeLowLevelSectionBean target = new AdvancedSectionChangeLowLevelSectionBean();

        // 4. 使用ProxyFactory生成代理对象并添加Advisor
        ProxyFactory proxyFactory = new ProxyFactory(target);
        proxyFactory.addAdvisors(advisors); // 注册所有通知的Advisor

        // 5. 获取代理对象(JDK动态代理或CGLIB,取决于目标类是否实现接口)
        AdvancedSectionChangeLowLevelSectionBean proxy = (AdvancedSectionChangeLowLevelSectionBean) proxyFactory.getProxy();

        // 6. 调用代理对象的方法,触发通知
        log.info("调用代理对象的foo()方法...");
        proxy.foo();

        log.info("\n调用代理对象的bar()方法(将抛出异常)...");
        try {
            proxy.bar();
        } catch (RuntimeException e) {
            log.error("捕获到bar()方法抛出的异常: {}", e.getMessage());
        }
    }


    /**
     * 解析切面类中的通知方法,生成对应的Advisor
     */
    private static List<Advisor> parseAspectMethods(AspectInstanceFactory aspectFactory) {
        List<Advisor> advisors = new ArrayList<>();
        Method[] methods = AdvancedAspect.class.getDeclaredMethods();

        for (Method method : methods) {
            // 跳过无通知注解的方法(如普通工具方法)
            if (!hasAopAnnotation(method)) {
                continue;
            }

            // 解析切点表达式(从@Before/@After等注解中获取)
            String pointcutExpr = getPointcutExpression(method);
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression(pointcutExpr);

            // 根据通知类型创建对应的Advice对象
            Advice advice = createAdvice(method, pointcut, aspectFactory);

            // 创建Advisor(切点+通知的组合)
            advisors.add(new DefaultPointcutAdvisor(pointcut, advice));
            log.info("注册Advisor:{}", advice);
        }
        return advisors;
    }

    /**
     * 判断方法是否包含AOP通知注解
     */
    private static boolean hasAopAnnotation(Method method) {
        return method.isAnnotationPresent(Before.class) || method.isAnnotationPresent(After.class) || method.isAnnotationPresent(AfterReturning.class) || method.isAnnotationPresent(AfterThrowing.class) || method.isAnnotationPresent(Around.class);
    }

    /**
     * 从方法注解中提取切点表达式(优先使用@Pointcut定义的表达式)
     */
    private static String getPointcutExpression(Method method) {
        AfterThrowing afterThrowing = method.getAnnotation(AfterThrowing.class);
        if (afterThrowing != null && !afterThrowing.pointcut().isEmpty()) {
            return afterThrowing.pointcut();
        }
        AfterReturning afterReturning = method.getAnnotation(AfterReturning.class);
        if (afterReturning != null && !afterReturning.pointcut().isEmpty()) {
            return afterReturning.pointcut();
        }
        After after = method.getAnnotation(After.class);
        if (after != null) {
            return after.value();
        }
        Before before = method.getAnnotation(Before.class);
        if (before != null && !before.value().isEmpty()) {
            return before.value();
        }
        Around around = method.getAnnotation(Around.class);
        if (around != null && !around.value().isEmpty()) {
            return around.value();
        }
        // 默认使用方法名作为切点(示例用)
        return "execution(* com.dwl.advisor_aspect..*.foo())";
    }

    /**
     * 根据通知类型创建对应的Advice对象
     */
    private static Advice createAdvice(Method method, AspectJExpressionPointcut pointcut, AspectInstanceFactory factory) {
        if (method.isAnnotationPresent(Before.class)) {
            return new AspectJMethodBeforeAdvice(method, pointcut, factory);
        } else if (method.isAnnotationPresent(After.class)) {
            return new AspectJAfterAdvice(method, pointcut, factory);
        } else if (method.isAnnotationPresent(AfterReturning.class)) {
            return new AspectJAfterReturningAdvice(method, pointcut, factory);
        } else if (method.isAnnotationPresent(AfterThrowing.class)) {
            return new AspectJAfterThrowingAdvice(method, pointcut, factory);
        } else if (method.isAnnotationPresent(Around.class)) {
            // @Around通知需要特殊处理,使用AspectJAroundAdvice
            return new AspectJAroundAdvice(method, pointcut, factory);
        }
        throw new IllegalArgumentException("未知的通知类型:" + method.getName());
    }

    /**
     * 模拟Spring容器注册Advisor(实际通过BeanFactory的addAdvisors方法)
     */
    private static void registerAdvisorsToContainer(List<Advisor> advisors) {
        log.info("\n===== 已注册的Advisor列表 =====");
        advisors.forEach(advisor -> log.info("Advisor:{}", advisor));
    }

    /**
     * 切面类:包含5种通知方式的示例方法
     */
    static class AdvancedAspect {

        // 公共切点(避免重复定义)
        @Pointcut("execution(* com.dwl.advisor_aspect..*.foo())")
        public void fooPointcut() {
        }

        @Pointcut("execution(* com.dwl.advisor_aspect..*.bar())")
        public void barPointcut() {
        }

        /**
         * Before通知:目标方法执行前触发 场景:参数校验、权限检查、日志记录(方法开始)
         */
        @Before("fooPointcut()")
        public void beforeFoo(JoinPoint joinPoint) {
            log.info("[@Before] 前置通知 - 目标方法:{},参数:{}", joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
        }

        /**
         * After通知:目标方法执行后触发(无论成功或异常) 场景:资源清理(如关闭连接)、最终日志记录
         */
        @After("barPointcut()")
        public void afterBar(JoinPoint joinPoint) {
            log.info("[@After] 后置通知 - 目标方法:{}(无论成功或异常都会执行)", joinPoint.getSignature().getName());
        }

        /**
         * AfterReturning通知:目标方法成功返回后触发 场景:结果处理、日志记录(方法成功结束)
         */
        @AfterReturning(pointcut = "fooPointcut()", returning = "result")
        public void afterReturningFoo(JoinPoint joinPoint, Object result) {
            log.info("[@AfterReturning] 成功返回通知 - 目标方法:{},返回值:{}", joinPoint.getSignature().getName(), result != null ? result.getClass().getSimpleName() : "void");
        }

        /**
         * AfterThrowing通知:目标方法抛出异常后触发 场景:异常监控、事务回滚、错误日志记录
         */
        @AfterThrowing(pointcut = "barPointcut()", throwing = "ex")
        public void afterThrowingBar(JoinPoint joinPoint, Exception ex) {
            log.error("[@AfterThrowing] 异常通知 - 目标方法:{},异常:{}", joinPoint.getSignature().getName(), ex.getMessage());
        }

        /**
         * Around通知:包围目标方法,控制其执行流程 场景:事务管理(开启/提交事务)、限流(判断是否允许执行)、耗时统计
         */
        @Around("execution(* com.dwl.advisor_aspect..*.specialMethod())")
        public Object aroundSpecialMethod(ProceedingJoinPoint joinPoint) throws Throwable {
            log.info("[@Around] 环绕通知 - 开始执行目标方法:{}", joinPoint.getSignature().getName());
            long start = System.currentTimeMillis();
            try {
                // 调用目标方法(必须显式调用proceed(),否则目标方法不会执行)
                Object result = joinPoint.proceed();
                log.info("[@Around] 环绕通知 - 目标方法执行成功,耗时:{}ms,结果:{}", System.currentTimeMillis() - start, result != null ? result.getClass().getSimpleName() : "void");
                return result;
            } catch (Throwable e) {
                log.error("[@Around] 环绕通知 - 目标方法执行失败,耗时:{}ms,异常:{}", System.currentTimeMillis() - start, e.getMessage());
                throw e; // 重新抛出异常,确保上层能感知
            }
        }
    }

    /**
     * 目标Bean:包含被切点匹配的方法(foo/bar/specialMethod)
     */
    static class AdvancedSectionChangeLowLevelSectionBean {

        /**
         * 被@Before/@AfterReturning匹配的方法
         */
        public void foo() {
            log.info("[目标方法] foo() 执行中...");
        }

        /**
         * 被@After/@AfterThrowing匹配的方法(故意抛出异常)
         */
        public void bar() {
            log.info("[目标方法] bar() 执行中...");
            throw new RuntimeException("bar() 方法抛出异常");
        }

        /**
         * 被@Around匹配的特殊方法(用于演示环绕通知)
         */
        public String specialMethod() {
            log.info("[目标方法] specialMethod() 执行中...");
            return "success";
        }
    }
}
package com.dwl.advisor_aspect;

import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * @ClassName AdvisorAspectCase
 * @Description 演示Spring AOP中注解切面与编程式切面的协同工作,包含详细底层机制注释和调试日志
 * @Version 1.0.0
 * @Date 2025
 * @Author By Dwl
 */
@Slf4j
public class AdvisorAspectCase {


    public static void main(String[] args) {
        log.info("===== 开始初始化Spring应用上下文 =====");

        // 1. 创建通用应用上下文
        GenericApplicationContext context = new GenericApplicationContext();
        log.debug("已创建GenericApplicationContext实例:{}", context);

        // 2. 注册业务相关Bean
        context.registerBean("lowerAspect", LowerAspect.class);       // 编程式切面配置类
        context.registerBean("seniorAspect", SeniorAspect.class);     // 注解式切面类
        context.registerBean("advisorAspectBeanA", AdvisorAspectBeanA.class);  // 目标对象A(被切面增强)
        context.registerBean("advisorAspectBeanB", AdvisorAspectBeanB.class);  // 目标对象B(无切面匹配)

        // 3. 注册Spring核心后处理器(必须)
        // ConfigurationClassPostProcessor:解析@Configuration类并注册Bean定义
        context.registerBean(ConfigurationClassPostProcessor.class);
        // AnnotationAwareAspectJAutoProxyCreator:Spring AOP核心后处理器,负责生成代理对象
        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
        log.debug("已注册AOP核心后处理器:ConfigurationClassPostProcessor和AnnotationAwareAspectJAutoProxyCreator");

        // 4. 触发上下文刷新(关键生命周期阶段)
        context.refresh();
        log.info("===== Spring应用上下文初始化完成 =====");

        // 5. 获取代理对象并调用目标方法(触发切面逻辑)
        AdvisorAspectBeanA beanA = context.getBean("advisorAspectBeanA", AdvisorAspectBeanA.class);
        log.debug("获取到的AdvisorAspectBeanA实例类型:{}", beanA.getClass());  // 应显示代理类

        log.info("\n===== 调用目标对象A的foo()方法(触发切面) =====");
        beanA.foo();

        AdvisorAspectBeanB beanB = context.getBean("advisorAspectBeanB", AdvisorAspectBeanB.class);
        log.debug("获取到的AdvisorAspectBeanB实例类型:{}", beanB.getClass());  // 应为原始类(无切面匹配)

        log.info("\n===== 调用目标对象B的bar()方法(无切面匹配) =====");
        beanB.bar();

        // 6. 关闭上下文(销毁Bean、释放资源)
        context.close();
        log.info("===== Spring应用上下文已关闭 =====");
    }

    /**
     * 注解式高级切面(@Aspect驱动)
     * 底层机制:Spring通过AnnotationAwareAspectJAutoProxyCreator扫描@Aspect注解类,
     * 解析其中的通知方法(@Before/@After等),生成对应的Advisor并应用到匹配的目标Bean
     */
    @Aspect
    static class SeniorAspect {
        private static final String FOO_METHOD_POINTCUT = "execution(* com.dwl.advisor_aspect..*.foo())";

        /**
         * 前置通知:目标方法执行前触发
         * 底层流程:
         * 1. 通过JoinPoint获取目标方法元信息(类名、方法名、参数等)
         * 2. 执行通知逻辑(日志记录)
         * 3. 不会阻止目标方法执行(除非抛出异常)
         */
        @Before(FOO_METHOD_POINTCUT)
        public void before(JoinPoint joinPoint) {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            Object[] args = joinPoint.getArgs();

            log.info("[高级注解切面] 前置通知 | 目标类:{} | 方法:{} | 参数:{}",
                    joinPoint.getTarget().getClass().getSimpleName(),
                    method.getName(),
                    Arrays.toString(args));
        }

        /**
         * 后置通知:目标方法执行后触发(无论正常返回或异常)
         * 底层差异:@After通知不接收返回值,仅能访问JoinPoint基本信息
         */
        @After(FOO_METHOD_POINTCUT)
        public void after(JoinPoint joinPoint) {
            log.info("[高级注解切面] 后置通知 | 目标类:{} | 方法:{}",
                    joinPoint.getTarget().getClass().getSimpleName(),
                    ((MethodSignature) joinPoint.getSignature()).getMethod().getName());
        }
    }

    /**
     * 编程式低级切面(手动配置Advisor)
     * 底层机制:通过编程方式组合Pointcut(切点)和Advice(通知),由Spring自动应用到匹配的Bean
     */
    @Configuration
    static class LowerAspect {
        private static final String FOO_METHOD_POINTCUT_EXPRESSION =
                "execution(* com.dwl.advisor_aspect..*.foo())";

        /**
         * 定义编程式Advisor Bean
         * 底层逻辑:
         * 1. AspectJExpressionPointcut:解析切点表达式,匹配目标方法
         * 2. DefaultPointcutAdvisor:将切点与通知(MethodInterceptor)绑定
         * 3. Spring会将此Advisor应用到所有匹配切点表达式的Bean
         */
        @Bean
        public Advisor beforeAdviceAdvisor(MethodInterceptor interceptor) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression(FOO_METHOD_POINTCUT_EXPRESSION);

            // 调试:输出切点匹配的目标Bean名称(需手动实现Pointcut匹配逻辑)
            log.debug("创建编程式Advisor | 切点表达式:'{}' | 通知类型:{}",
                    pointcut.getExpression(),
                    interceptor.getClass().getSimpleName());

            return new DefaultPointcutAdvisor(pointcut, interceptor);
        }

        /**
         * 定义环绕通知(MethodInterceptor实现)
         * 底层特性:
         * - 环绕通知是最强大的通知类型,可完全控制目标方法执行(包括是否执行、参数修改、返回值修改)
         * - 通过MethodInvocation参数访问目标方法元信息和执行控制
         */
        @Bean
        public MethodInterceptor debugInterceptor() {
            return invocation -> {
                // 1. 前置处理:记录方法调用信息
                Class<?> targetClass = invocation.getClass();
                Method method = invocation.getMethod();
                Object[] args = invocation.getArguments();

                log.info("[编程式环绕通知] 前置处理 | 目标类:{} | 方法:{} | 参数:{}",
                        targetClass.getSimpleName(),
                        method.getName(),
                        Arrays.toString(args));

                long startTime = System.currentTimeMillis();

                try {
                    // 2. 执行目标方法(核心业务逻辑)
                    Object result = invocation.proceed();

                    // 3. 后置处理(成功返回)
                    log.info("[编程式环绕通知] 后置处理(成功) | 目标类:{} | 方法:{} | 返回值类型:{} | 耗时:{}ms",
                            targetClass.getSimpleName(),
                            method.getName(),
                            result != null ? result.getClass().getSimpleName() : "void",
                            System.currentTimeMillis() - startTime);
                    return result;
                } catch (Throwable t) {
                    // 4. 异常处理(失败返回)
                    log.error("[编程式环绕通知] 异常处理 | 目标类:{} | 方法:{} | 异常:{}",
                            targetClass.getSimpleName(),
                            method.getName(),
                            t.getMessage());
                    throw t;
                }
            };
        }
    }

    /**
     * 目标对象A:包含被切面匹配的方法foo()
     * 底层特征:被Spring管理后会被包装为代理对象(JDK动态代理或CGLIB)
     */
    static class AdvisorAspectBeanA {
        /**
         * 核心业务方法(被高级注解切面和编程式切面共同匹配)
         * 切点表达式匹配条件:com.dwl.advisor_aspect包下任意类的foo()方法
         */
        public void foo() {
            log.info("[目标对象A] 执行核心逻辑 | foo()方法");
        }
    }

    /**
     * 目标对象B:包含未被切面匹配的方法bar()
     * 底层特征:无切面增强,直接调用原始方法
     */
    static class AdvisorAspectBeanB {
        /**
         * 未被切面匹配的方法(切点表达式仅匹配foo())
         */
        public void bar() {
            log.info("[目标对象B] 执行核心逻辑 | bar()方法");
        }
    }

}
package com.dwl.advisor_aspect;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

/**
 * @ClassName FindEligibleAdvisorCase
 * @Description 演示Spring AOP中自动代理创建器如何查找并筛选适用于目标Bean的切面(Advisors)
 * 包含反射调用内部方法、切面类型解析、编程式/注解式切面对比等核心机制
 * @Version 1.0.0
 * @Date 2025
 * @Author By Dwl
 */
@Slf4j
public class FindEligibleAdvisorCase {


    public static void main(String[] args) {
        log.info("===== 开始初始化Spring应用上下文 =====");

        // 1. 创建非Web环境的通用应用上下文
        GenericApplicationContext context = new GenericApplicationContext();
        log.debug("已创建GenericApplicationContext实例:{}", context);

        // 2. 注册业务相关Bean
        // - 编程式切面配置类(定义低级切面)
        context.registerBean("lowerAspect", AdvisorAspectCase.LowerAspect.class);
        // - 注解式切面类(@Aspect驱动的高级切面)
        context.registerBean("seniorAspect", AdvisorAspectCase.SeniorAspect.class);
        // - 目标对象A(被切面匹配的方法foo())
        context.registerBean("advisorAspectBeanA", AdvisorAspectCase.AdvisorAspectBeanA.class);
        // - 目标对象B(无匹配切面的方法bar())
        context.registerBean("advisorAspectBeanB", AdvisorAspectCase.AdvisorAspectBeanB.class);

        // 3. 注册Spring核心后处理器(必须)
        // ConfigurationClassPostProcessor:解析@Configuration类,注册Bean定义(包括@Aspect切面)
        context.registerBean(ConfigurationClassPostProcessor.class);
        // AnnotationAwareAspectJAutoProxyCreator:Spring AOP核心后处理器,负责生成代理对象
        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
        log.debug("已注册AOP核心后处理器:ConfigurationClassPostProcessor和AnnotationAwareAspectJAutoProxyCreator");

        // 4. 触发上下文刷新(关键生命周期阶段)
        // 流程:Bean定义加载 → Bean实例化 → 依赖注入 → AOP代理生成 → 初始化回调
        context.refresh();
        log.info("===== Spring应用上下文初始化完成 =====");

        // 5. 获取AnnotationAwareAspectJAutoProxyCreator实例(AOP自动代理创建器)
        AnnotationAwareAspectJAutoProxyCreator proxyCreator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
        log.debug("获取到AnnotationAwareAspectJAutoProxyCreator实例:{}", proxyCreator.getClass());

        // 6. 目标对象A的类信息(被切面匹配的类)
        Class<?> aspectBeanAclass = AdvisorAspectCase.AdvisorAspectBeanA.class;
        log.info("\n===== 分析目标对象A(AdvisorAspectBeanA)的适配切面 =====");
        // 通过反射调用私有方法findEligibleAdvisors,获取适用于目标类和Bean名称的切面列表
        List<Advisor> advisorsForA = getAdvisorsFromProxyCreator(proxyCreator, aspectBeanAclass, "advisorAspectBeanA");
        // 打印切面信息
        advisorsForA.forEach(advisor -> log.info("  - 切面类型:{} | 切面详情:{}", advisor.getClass().getSimpleName(), advisor));

        // 7. 目标对象B的类信息(无匹配切面的类)
        Class<?> aspectBeanBclass = AdvisorAspectCase.AdvisorAspectBeanB.class;
        log.info("\n===== 分析目标对象B(AdvisorAspectBeanB)的适配切面 =====");
        List<Advisor> advisorsForB = getAdvisorsFromProxyCreator(proxyCreator, aspectBeanBclass, "advisorAspectBeanB");
        log.info("  - 切面数量:{}(无匹配切面)", advisorsForB.size());
        advisorsForB.forEach(advisor -> log.info("  - 切面类型:{}", advisor.getClass().getSimpleName()));

        // 8. 关闭上下文(销毁Bean、释放资源)
        context.close();
        log.info("===== Spring应用上下文已关闭 =====");
    }


    /**
     * 通过反射调用AbstractAdvisorAutoProxyCreator的私有方法findEligibleAdvisors
     * 底层原理:Spring AOP自动代理创建器的核心方法,用于筛选适用于目标类和Bean名称的切面
     *
     * @param proxyCreator 自动代理创建器实例(AnnotationAwareAspectJAutoProxyCreator)
     * @param targetClass  目标对象的类
     * @param beanName     目标Bean的名称
     * @return 适配的切面列表
     */
    @SuppressWarnings("unchecked")
    private static List<Advisor> getAdvisorsFromProxyCreator(AnnotationAwareAspectJAutoProxyCreator proxyCreator,
                                                             Class<?> targetClass, String beanName) {
        try {
            // 1. 查找AbstractAdvisorAutoProxyCreator的私有方法findEligibleAdvisors
            // 方法签名:protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName)
            Method method = ReflectionUtils.findMethod(
                    AbstractAdvisorAutoProxyCreator.class,
                    "findEligibleAdvisors",
                    Class.class,
                    String.class
            );
            if (Objects.isNull(method)) {
                throw new NoSuchMethodException("未找到方法findEligibleAdvisors(Class, String)");
            }

            // 2. 设置方法可访问(私有方法需要反射授权)
            method.setAccessible(true);

            // 3. 反射调用方法,传入目标类和Bean名称
            /* 该方法会执行以下核心逻辑:
             * a. 收集所有已注册的Advisor(包括编程式和注解式切面转换后的Advisor)
             * b. 根据切点的匹配规则(pointcut)筛选出适用于targetClass的Advisor
             * c. 排除不匹配的Advisor(如切点表达式不匹配当前类或方法)*/
            return (List<Advisor>) method.invoke(proxyCreator, targetClass, beanName);
        } catch (Exception e) {
            log.error("反射调用findEligibleAdvisors失败:{}", e.getMessage(), e);
            return List.of();
        }
    }
}

/*
 * 扩展说明:Spring AOP中关键切面类型解析(基于日志输出)
 * <p>
 * 1. ExposeInvocationInterceptor.ADVISOR
 * - 类型:org.springframework.aop.interceptor.ExposeInvocationInterceptor$Advisor
 * - 来源:Spring AOP内部自动添加的切面,用于暴露当前方法调用(MethodInvocation)到线程上下文
 * - 作用:允许在通知(Advice)中通过AopContext.currentInvocation()获取当前方法调用信息
 * - 特性:所有代理对象都会自动包含此切面,优先级最低(最后执行)
 * <p>
 * 2. DefaultPointcutAdvisor(编程式切面)
 * - 类型:org.springframework.aop.support.DefaultPointcutAdvisor
 * - 来源:通过编程方式手动创建(LowerAspect中的beforeAdviceAdvisor方法)
 * - 组成:包含AspectJExpressionPointcut(切点表达式)和一个MethodInterceptor(环绕通知)
 * - 匹配规则:切点表达式execution(* com.dwl.advisor_aspect..*.foo())匹配目标类A的foo()方法
 * - 执行顺序:由Bean注册顺序决定(通常在内部切面之后,注解切面之前)
 * <p>
 * 3. InstantiationModelAwarePointcutAdvisor(注解式切面)
 * - 类型:org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisor
 * - 来源:由AnnotationAwareAspectJAutoProxyCreator将@Aspect切面转换为的低级Advisor
 * - 组成:包含AspectJ表达式切点(AspectJExpressionPointcut)和通知方法(@Before/@After对应的方法)
 * - 匹配规则:切点表达式与编程式切面相同,因此也会匹配目标类A的foo()方法
 * - 特性:支持@Order注解排序(本示例未显式设置,默认按Bean注册顺序)
 * - 执行顺序:优先级高于编程式切面(因@Aspect切面通常注册早于编程式配置类)
 * <p>
 * 目标对象B无切面的原因:
 * - 其方法bar()的切点表达式不匹配任何已定义的切面(切面仅匹配foo()方法)
 * - AnnotationAwareAspectJAutoProxyCreator在findEligibleAdvisors时会过滤掉不匹配的Advisor
 */package com.dwl.advisor_aspect;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

import javax.annotation.PostConstruct;

/**
 * @ClassName ProxyCreationTimingCase
 * @Description 演示Spring AOP代理的创建时机,通过两个独立的Spring上下文验证不同Bean间的代理行为
 * 核心流程:上下文刷新 -> 注册后置处理器 -> 实例化Bean -> 依赖注入 -> 初始化回调 -> 生成代理(按需)
 * 关键观察点:代理对象的生成时机、依赖注入的代理类型、初始化回调中的代理状态
 * @Version 1.0.0
 * @Date 2025
 * @Author By Dwl
 */
@Slf4j
public class ProxyCreationTimingCase {

    public static void main(String[] args) {

        // 第一个测试上下文:验证BeanA与BeanB的代理交互
        testContext("First Context", AopBeanPostConfig.class);
        // 第二个测试上下文:验证BeanC与BeanD的代理交互(模拟循环依赖场景)
        testContext("Second Context", AopBeanPostConfigA.class);
    }


    /**
     * 通用上下文测试方法,封装上下文创建、刷新、关闭流程
     *
     * @param contextName 上下文标识名称
     * @param configClass 配置类
     */
    private static void testContext(String contextName, Class<?> configClass) {
        log.info("{} 开始执行...", contextName);
        GenericApplicationContext context = new GenericApplicationContext();

        // 注册核心配置处理器(必须):负责解析@Configuration类并注册Bean定义
        context.registerBean(ConfigurationClassPostProcessor.class);
        // 注册自定义配置类(包含AOP相关Bean定义)
        context.registerBean(configClass);

        // 刷新上下文(核心流程触发点)
        context.refresh();

        // 关闭上下文(释放资源)
        context.close();
        log.info("{} 执行完成\n{}\n", contextName, "-".repeat(100));
    }

    /**
     * 第一个AOP配置类:注册基础AOP组件和测试BeanA/B
     * 包含:自动代理创建器、注解后处理器、编程式切面、测试Bean
     */
    @Configuration
    static class AopBeanPostConfig {

        /**
         * 注册AnnotationAwareAspectJAutoProxyCreator作为Bean后置处理器
         * 底层原理:
         * 1. 实现BeanPostProcessor接口,在Bean生命周期的"初始化后"阶段(postProcessAfterInitialization)介入
         * 2. 自动检测被@Aspect注解的类或通过编程方式注册的Advisor,为匹配切点的Bean生成代理
         * 3. 代理生成策略:优先JDK动态代理(要求目标类实现接口),否则CGLIB代理
         * 日志验证点:观察是否输出"显式注册AnnotationAwareAspectJAutoProxyCreator"
         */
        @Bean
        public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJautoProxyCreator() {
            AnnotationAwareAspectJAutoProxyCreator creator = new AnnotationAwareAspectJAutoProxyCreator();
            /* 设置代理模式为JDK动态代理(即使目标类未实现接口,也强制使用JDK代理,否则默认CGLIB)
             * 注意:实际开发中不建议强制设置,可能导致类型不匹配异常
             * creator.setProxyTargetClass(false); // 默认即为false(JDK代理)*/
            log.info("显式注册AnnotationAwareAspectJAutoProxyCreator(代理模式:默认JDK动态代理)");
            return creator;
        }

        /**
         * 注册AutowiredAnnotationBeanPostProcessor处理@Autowired注解
         * 底层原理:
         * 1. 实现BeanPostProcessor接口,在Bean实例化后(postProcessProperties)处理依赖注入
         * 2. 扫描Bean的字段、方法、参数上的@Autowired注解,从容器中解析对应Bean并注入
         * 3. 支持required属性(默认true),未找到Bean时抛出异常
         * 日志验证点:观察是否输出"显式注册AutowiredAnnotationBeanPostProcessor"
         */
        @Bean
        public AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor() {
            AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
            processor.setAutowiredAnnotationType(Autowired.class); // 显式指定注解类型(默认已包含)
            log.info("显式注册AutowiredAnnotationBeanPostProcessor(处理@Autowired注解)");
            return processor;
        }

        /**
         * 注册CommonAnnotationBeanPostProcessor处理JSR-250注解(如@PostConstruct)
         * 底层原理:
         * 1. 实现BeanPostProcessor接口,在Bean初始化阶段(postProcessBeforeInitialization)处理回调
         * 2. 扫描@PostConstruct注解的方法,在依赖注入完成后、初始化方法(如InitializingBean.afterPropertiesSet)前执行
         * 3. 遵循JSR-250规范,支持多初始化回调(@PostConstruct -> afterPropertiesSet -> init-method)
         * 日志验证点:观察是否输出"显式注册CommonAnnotationBeanPostProcessor"
         */
        @Bean
        public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() {
            CommonAnnotationBeanPostProcessor processor = new CommonAnnotationBeanPostProcessor();
            log.info("显式注册CommonAnnotationBeanPostProcessor(处理@PostConstruct等JSR-250注解)");
            return processor;
        }

        /**
         * 编程式创建方法拦截器(MethodInterceptor)
         * 底层原理:
         * 1. 实现AOP联盟的MethodInterceptor接口,定义通知(Advice)逻辑
         * 2. 通过invoke方法拦截目标方法调用,可在方法执行前后添加增强逻辑
         * 3. 与环绕通知(Around Advice)类似,但更轻量(仅前后处理,无ProceedingJoinPoint)
         * 日志验证点:观察是否输出"创建编程式切面前置/后置处理"
         */
        @Bean
        public MethodInterceptor programmaticInterceptor() {
            return invocation -> {
                // 前置处理:记录线程信息和目标方法
                String methodName = invocation.getMethod().getName();
                log.info("[编程式切面] 前置处理(线程:{},目标方法:{})",
                        Thread.currentThread().getName(), methodName);

                // 调用目标方法(触发后续通知和原始方法执行)
                Object result = invocation.proceed();

                // 后置处理:记录返回结果类型
                String resultType = result != null ? result.getClass().getSimpleName() : "void";
                log.info("[编程式切面] 后置处理(线程:{},结果类型:{})",
                        Thread.currentThread().getName(), resultType);

                return result;
            };
        }

        /**
         * 编程式创建Advisor(通知+切点组合)
         * 底层原理:
         * 1. Advisor是Spring AOP中表示"切点+通知"的核心接口
         * 2. DefaultPointcutAdvisor通过组合AspectJExpressionPointcut(切点)和MethodInterceptor(通知)工作
         * 3. 切点表达式"execution(* com.dwl.advisor_aspect..*.foo())"匹配所有包下以foo()结尾的方法
         * 日志验证点:观察是否输出"创建编程式Advisor:切点表达式=..."
         */
        @Bean
        public Advisor programmaticAdvisor(MethodInterceptor interceptor) {
            // 定义AspectJ切点表达式(匹配所有foo()方法)
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* com.dwl.advisor_aspect..*.foo())"); // 切点表达式
            // 验证切点表达式匹配的Bean(调试用)
            log.debug("创建编程式Advisor:切点表达式='{}',通知类型={}",
                    pointcut.getExpression(), interceptor.getClass().getSimpleName());

            // 组合切点和通知生成Advisor
            return new DefaultPointcutAdvisor(pointcut, interceptor);
        }


        @Bean
        public ProxyCreationTimingBeanA timingBeanA() {
            log.info("[显式配置] 注册ProxyCreationTimingBeanA Bean定义(构造器调用前)");
            return new ProxyCreationTimingBeanA();
        }

        @Bean
        public ProxyCreationTimingBeanB timingBeanB() {
            log.info("[显式配置] 注册ProxyCreationTimingBeanB Bean定义(构造器调用前)");
            return new ProxyCreationTimingBeanB();
        }
    }

    /**
     * 测试BeanA:无依赖,验证构造器、@PostConstruct、代理生成时机
     * 生命周期顺序验证点:
     * 1. 构造器执行(实例化阶段)
     * 2. @Autowired注入(属性注入阶段)
     * 3. @PostConstruct执行(初始化回调阶段)
     * 4. 代理生成(初始化后阶段,由AnnotationAwareAspectJAutoProxyCreator处理)
     */
    static class ProxyCreationTimingBeanA {

        /**
         * 构造器执行时机:
         * - 在Bean实例化阶段首先调用(通过反射调用无参构造器)
         * - 此时Bean尚未进行属性注入、初始化回调,更未生成代理
         * - 日志输出的类类型为原始类(ProxyCreationTimingBeanA)
         * 2025-07-23 18:12:41.088 [main] TRACE o.s.a.a.a.AnnotationAwareAspectJAutoProxyCreator.buildAdvisors:580 - Creating implicit proxy for bean 'timingBeanA' with 0 common interceptors and 2 specific interceptors
         */
        public ProxyCreationTimingBeanA() {
            log.info("[ProxyCreationTimingBeanA] 构造器执行(Bean实例化阶段) - 类型:{}", this.getClass());
        }

        /**
         * 目标方法:被切面匹配(execution(* *.foo())),将被代理拦截
         */
        public void foo() {
            log.info("[ProxyCreationTimingBeanA] 执行foo()方法 - 实例类型:{}", this.getClass());
        }

        /**
         * PostConstruct回调执行时机:
         * - 在依赖注入完成后(@Autowired执行后)
         * - 在初始化方法(如InitializingBean.afterPropertiesSet)前
         * - 此时如果Bean被代理,实际执行的是代理对象的@PostConstruct方法
         * (代理会先执行通知逻辑,再调用目标对象的@PostConstruct)
         */
        @PostConstruct
        public void postConstruct() {
            log.info("[ProxyCreationTimingBeanA] @PostConstruct执行(初始化回调阶段) - 类型:{}", this.getClass());
        }
    }

    /**
     * 测试BeanB:依赖BeanA,验证依赖注入的代理类型
     * 关键验证点:
     * 1. BeanB构造时,BeanA是否已被代理?
     * 2. 注入的BeanA类型是原始类还是代理类?
     * 3. 依赖注入阶段(@Autowired)发生在代理生成前还是后?
     */
    @Data
    static class ProxyCreationTimingBeanB {
        private ProxyCreationTimingBeanA timingBeanA;

        /**
         * 构造器执行时机:
         * - 在Bean实例化阶段调用(早于依赖注入和初始化回调)
         * - 此时BeanA尚未被注入,日志输出的BeanA类型为null
         */
        public ProxyCreationTimingBeanB() {
            log.info("[ProxyCreationTimingBeanB] 构造器执行(Bean实例化阶段)");
        }

        /**
         * Autowired注入BeanA:
         * - 由AutowiredAnnotationBeanPostProcessor在属性注入阶段处理
         * - 注入的BeanA可能是代理对象(如果被切面匹配)
         * - 日志输出注入对象的类型,验证是否为代理类
         */
        @Autowired
        public void setBeanA(ProxyCreationTimingBeanA beanA) {
            this.timingBeanA = beanA;
            log.info("[ProxyCreationTimingBeanB] 注入BeanA - 代理类型:{}", beanA.getClass());
        }

        /**
         * PostConstruct回调:
         * - 在依赖注入完成后执行(此时BeanA已注入)
         * - 验证@PostConstruct执行时,BeanA的代理状态
         */
        @PostConstruct
        public void postConstruct() {
            log.info("[ProxyCreationTimingBeanB] @PostConstruct执行(初始化回调阶段) - BeanA类型:{}", timingBeanA.getClass());
        }
    }

    /**
     * 第二个AOP配置类:注册基础AOP组件和测试BeanC/D(模拟循环依赖)
     * 验证循环依赖场景下的代理生成和注入行为
     */
    @Configuration
    static class AopBeanPostConfigA {

        @Bean
        public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJautoProxyCreator() {
            AnnotationAwareAspectJAutoProxyCreator creator = new AnnotationAwareAspectJAutoProxyCreator();
            log.info("显式注册AnnotationAwareAspectJAutoProxyCreator(代理模式:默认JDK动态代理)");
            return creator;
        }

        @Bean
        public AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor() {
            AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
            processor.setAutowiredAnnotationType(Autowired.class);
            log.info("显式注册AutowiredAnnotationBeanPostProcessor(处理@Autowired注解)");
            return processor;
        }

        @Bean
        public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() {
            CommonAnnotationBeanPostProcessor processor = new CommonAnnotationBeanPostProcessor();
            log.info("显式注册CommonAnnotationBeanPostProcessor(处理@PostConstruct等注解)");
            return processor;
        }

        @Bean
        public MethodInterceptor programmaticInterceptor() {
            return invocation -> {
                log.info("[编程式切面] 前置处理(线程:{})", Thread.currentThread().getName());
                Object result = invocation.proceed();
                log.info("[编程式切面] 后置处理(结果类型:{})",
                        result != null ? result.getClass().getSimpleName() : "void");
                return result;
            };
        }

        @Bean
        public Advisor programmaticAdvisor(MethodInterceptor interceptor) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* com.dwl.advisor_aspect..*.foo())"); // 切点表达式
            log.debug("创建编程式Advisor:切点表达式='{}',通知类型={}",
                    pointcut.getExpression(), interceptor.getClass().getSimpleName());
            return new DefaultPointcutAdvisor(pointcut, interceptor);
        }

        @Bean
        public ProxyCreationTimingBeanC timingBeanC() {
            log.info("[显式配置] 注册ProxyCreationTimingBeanC Bean定义(构造器调用前)");
            return new ProxyCreationTimingBeanC();
        }

        @Bean
        public ProxyCreationTimingBeanD timingBeanD() {
            log.info("[显式配置] 注册ProxyCreationTimingBeanD Bean定义(构造器调用前)");
            return new ProxyCreationTimingBeanD();
        }
    }

    /**
     * 测试BeanC:依赖BeanD,模拟循环依赖场景
     */
    @Data
    static class ProxyCreationTimingBeanC {

        public void foo() {
        }

        public ProxyCreationTimingBeanC() {
            log.info("[ProxyCreationTimingBeanC] 构造器执行(Bean实例化阶段)");
        }

        @Autowired
        public void setBeanA(ProxyCreationTimingBeanD beanD) {
            log.info("[ProxyCreationTimingBeanC] 注入BeanD - 代理类型:{}", beanD.getClass());
        }

        @PostConstruct
        public void postConstruct() {
            log.info("[ProxyCreationTimingBeanC] @PostConstruct执行(初始化回调阶段)");
        }
    }

    /**
     * 测试BeanD:依赖BeanC,完成循环依赖
     */
    @Data
    static class ProxyCreationTimingBeanD {

        public ProxyCreationTimingBeanD() {
            log.info("[ProxyCreationTimingBeanD] 构造器执行(Bean实例化阶段)");
        }

        @Autowired
        public void setBeanA(ProxyCreationTimingBeanC beanC) {
            log.info("[ProxyCreationTimingBeanD] 注入BeanC - 代理类型:{}", beanC.getClass());
        }

        @PostConstruct
        public void postConstruct() {
            log.info("[ProxyCreationTimingBeanD] @PostConstruct执行(初始化回调阶段)");
        }
    }

}
package com.dwl.advisor_aspect;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @ClassName WrapIfNecessaryCase
 * @Description 演示Spring AOP中AnnotationAwareAspectJAutoProxyCreator的wrapIfNecessary方法核心逻辑
 * 包含代理创建条件判断、代理对象生成流程、反射调用私有方法等底层机制解析
 * @Version 1.0.0
 * @Date 2025
 * @Author By Dwl
 */
@Slf4j
public class WrapIfNecessaryCase {


    /**
     * WrapIfNecessary判断是否有必要为目标创建代理
     */
    public static void main(String[] args) {

        log.info("===== 开始初始化Spring应用上下文 =====");

        // 1. 创建非Web环境的通用应用上下文
        GenericApplicationContext context = new GenericApplicationContext();
        log.debug("已创建GenericApplicationContext实例:{}", context);

        // 2. 注册业务相关Bean
        // - 编程式切面配置类(定义低级切面)
        context.registerBean("lowerAspect", AdvisorAspectCase.LowerAspect.class);
        // - 注解式切面类(@Aspect驱动的高级切面)
        context.registerBean("seniorAspect", AdvisorAspectCase.SeniorAspect.class);
        // - 目标对象A(被切面匹配的方法foo())
        context.registerBean("advisorAspectBeanA", AdvisorAspectCase.AdvisorAspectBeanA.class);
        // - 目标对象B(无匹配切面的方法bar())
        context.registerBean("advisorAspectBeanB", AdvisorAspectCase.AdvisorAspectBeanB.class);

        // 3. 注册Spring核心后处理器(必须)
        // ConfigurationClassPostProcessor:解析@Configuration类,注册Bean定义(包括@Aspect切面)
        context.registerBean(ConfigurationClassPostProcessor.class);
        // AnnotationAwareAspectJAutoProxyCreator:Spring AOP核心后处理器,负责生成代理对象
        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
        log.debug("已注册AOP核心后处理器:ConfigurationClassPostProcessor和AnnotationAwareAspectJAutoProxyCreator");

        // 4. 触发上下文刷新(关键生命周期阶段)
        // 流程:Bean定义加载 → Bean实例化 → 依赖注入 → AOP代理生成 → 初始化回调
        context.refresh();
        log.info("===== Spring应用上下文初始化完成 =====");

        // 5. 获取AnnotationAwareAspectJAutoProxyCreator实例(AOP自动代理创建器)
        AnnotationAwareAspectJAutoProxyCreator proxyCreator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
        log.debug("获取到AnnotationAwareAspectJAutoProxyCreator实例:{}", proxyCreator.getClass());

        // 6. 目标对象A(有匹配切面)的代理生成验证
        log.info("\n===== 验证目标对象A(AdvisorAspectBeanA)的代理生成 =====");
        Object proxiedA = wrapBeanWithProxy(proxyCreator, new AdvisorAspectCase.AdvisorAspectBeanA(), "advisorAspectBeanA");
        validateProxyResult(proxiedA, AdvisorAspectCase.AdvisorAspectBeanA.class);

        // 7. 目标对象B(无匹配切面)的代理生成验证
        log.info("\n===== 验证目标对象B(AdvisorAspectBeanB)的代理生成 =====");
        Object proxiedB = wrapBeanWithProxy(proxyCreator, new AdvisorAspectCase.AdvisorAspectBeanB(), "advisorAspectBeanB");
        validateProxyResult(proxiedB, AdvisorAspectCase.AdvisorAspectBeanB.class);

        // 8. 关闭上下文(销毁Bean、释放资源)
        context.close();
        log.info("===== Spring应用上下文已关闭 =====");
    }


    /**
     * 验证代理生成结果的辅助方法
     *
     * @param proxied     目标对象或其代理
     * @param targetClass 原始目标对象的类
     */
    private static void validateProxyResult(Object proxied, Class<?> targetClass) {
        String originalTypeName = targetClass.getSimpleName();
        String proxiedTypeName = proxied.getClass().getSimpleName();
        boolean isProxy = !proxied.getClass().equals(targetClass);

        log.info("原始对象类型:{} | 代理对象类型:{} | 是否为代理:{}",
                originalTypeName, proxiedTypeName, isProxy ? "是" : "否");
    }

    /**
     * 通过反射调用AnnotationAwareAspectJAutoProxyCreator的私有方法wrapIfNecessary
     * 底层原理:Spring AOP自动代理创建器的核心决策方法,用于判断是否需要为目标对象生成代理
     *
     * @param proxyCreator 自动代理创建器实例(AnnotationAwareAspectJAutoProxyCreator)
     * @param target       目标对象原始实例
     * @param beanName     目标Bean在容器中的名称
     * @return 代理对象(若需要)或原始对象(若不需要)
     */
    private static Object wrapBeanWithProxy(AnnotationAwareAspectJAutoProxyCreator proxyCreator,
                                            Object target,
                                            String beanName) {
        try {
            // 1. 查找AnnotationAwareAspectJAutoProxyCreator的私有方法wrapIfNecessary
            // 方法签名:protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey)
            Method method = ReflectionUtils.findMethod(
                    AnnotationAwareAspectJAutoProxyCreator.class,
                    "wrapIfNecessary",
                    Object.class,
                    String.class,
                    Object.class
            );
            if (Objects.isNull(method)) {
                throw new NoSuchMethodException("未找到方法wrapIfNecessary(Object, String, Object)");
            }

            // 2. 设置方法可访问(私有方法需要反射授权)
            method.setAccessible(true);

            // 3. 反射调用方法,传入目标对象、Bean名称和缓存键(此处缓存键与目标对象相同)
            /* 该方法会执行以下核心逻辑:
             * a. 调用findEligibleAdvisors获取适用于当前Bean的切面列表(即前一示例中的适配切面)
             * b. 如果切面列表非空(存在匹配的切面),则调用createProxy生成代理对象
             * c. 如果切面列表为空(无匹配的切面),则直接返回原始对象 */
            return method.invoke(proxyCreator, target, beanName, target);
        } catch (Exception e) {
            log.error("反射调用wrapIfNecessary失败:{}", e.getMessage(), e);
            return target; // 异常时返回原始对象
        }
    }
}

/*
 * 扩展说明:Spring AOP中wrapIfNecessary方法核心逻辑解析
 * <p>
 * 1. 方法定位与作用:
 * wrapIfNecessary是AbstractAutoProxyCreator(AnnotationAwareAspectJAutoProxyCreator的父类)的受保护方法,
 * 是Spring AOP决定是否生成代理的核心决策点。其核心逻辑可概括为:
 * "如果目标Bean存在匹配的切面(通过findEligibleAdvisors获取非空Advisor列表),则为Bean生成代理;否则返回原始Bean"
 * <p>
 * 2. 关键执行流程:
 * a. 判断是否需要代理:
 * - 调用findEligibleAdvisors(beanClass, beanName)获取适配的切面列表
 * - 若列表非空(存在至少一个匹配的Advisor),则进入代理生成流程
 * - 若列表为空(无匹配的切面),直接返回原始对象
 * b. 生成代理对象:
 * - 确定代理模式(JDK动态代理或CGLIB):根据目标类是否实现接口选择(默认优先接口)
 * - 应用切面逻辑:将匹配的Advisor转换为AOP代理的拦截器链
 * - 包装原始对象:通过InvocationHandler(JDK)或MethodInterceptor(CGLIB)拦截方法调用并执行切面逻辑
 * <p>
 * 3. 目标对象A与B的代理差异原因:
 * - 目标对象A(AdvisorAspectBeanA)的foo()方法被编程式切面(DefaultPointcutAdvisor)和注解式切面(InstantiationModelAwarePointcutAdvisor)匹配,
 * 因此findEligibleAdvisors返回非空列表,wrapIfNecessary会生成代理对象(JDK或CGLIB)。
 * - 目标对象B(AdvisorAspectBeanB)的bar()方法无任何切面匹配,findEligibleAdvisors返回空列表,因此wrapIfNecessary直接返回原始对象。
 * <p>
 * 4. 反射调用的必要性:
 * wrapIfNecessary是protected方法,无法直接通过Spring API调用。通过反射调用可以绕过访问限制,
 * 直接验证Spring内部的代理生成决策逻辑是否符合预期(如切面匹配规则、代理生成条件)。
 */