引言
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、任意参数的方法(*表示任意返回值,..表示任意参数)。
- 类过滤器(ClassFilter):匹配所有包路径下以
-
DefaultPointcutAdvisor的组装:
该类持有Pointcut和Advice(此处是MethodInterceptor),是Spring AOP中“切点+通知”的最小执行单元。当后续代理生成时,Spring会将所有匹配的Advisor的Advice按顺序编织到代理的拦截器链中。
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生成
对于SeniorAspect的before方法(标注@Before):
@Before("execution(* com.dwl.advisor_aspect..*.foo())")
public void before(JoinPoint joinPoint) { ... }
- 切点表达式的解析:
@Before的value属性(或pointcut属性)会被解析为Pointcut对象。若表达式为空,则使用默认切点(匹配所有目标类方法)。 - 通知类型的映射:
@Before对应MethodBeforeAdvice,@After对应AfterAdvice,@Around对应MethodInterceptor(最强大)。Spring会将这些通知适配为Advice接口的实现类(如MethodBeforeAdviceAdapter)。 - Advisor的生成:
最终生成InstantiationModelAwarePointcutAdvisor,该类持有切点(Pointcut)和通知(Advice),并记录切面的实例化模型(如PER_THIS、PER_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会调用其Pointcut的matches方法,判断是否适用于当前目标类(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会将匹配结果缓存到methodCache(ConcurrentHashMap)中,键为(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生成代理类,核心步骤如下:
- 生成代理类字节码:
JVM动态生成一个继承自Proxy的类(如com.dwl.advisor_aspect.ProxyCreationTimingBeanA$$Proxy),该类实现了目标类的所有接口。 - 实现InvocationHandler:
代理类的invoke方法会调用InvocationHandler的invoke方法,后者负责执行切面逻辑(拦截器链)和目标方法。
示例代理类字节码(简化):
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类生成目标类的子类,核心步骤如下:
- 生成子类字节码:
使用ASM库动态生成目标类的子类(如ProxyCreationTimingBeanA$$EnhancerBySpringCGLIB$$123456),重写目标方法。 - 方法拦截:
子类中重写的方法会调用MethodInterceptor的intercept方法,后者负责执行切面逻辑和调用父类(目标类)的方法。
示例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通过三级缓存解决循环依赖:
- 一级缓存(singletonObjects):存储已完全初始化的单例Bean。
- 二级缓存(earlySingletonObjects):存储提前暴露的Bean引用(未完成初始化)。
- 三级缓存(singletonFactories):存储Bean工厂(用于生成早期引用)。
5.2 代理在循环依赖中的行为
假设BeanA依赖BeanB,BeanB依赖BeanA,且两者均被AOP代理:
- BeanA的初始化:
Spring创建BeanA的原始对象,发现其依赖BeanB,于是尝试注入BeanB。 - BeanB的初始化:
Spring创建BeanB的原始对象,发现其依赖BeanA,于是尝试注入BeanA。此时BeanA尚未完成初始化,但三级缓存中已有BeanA的工厂(BeanFactory)。 - 提前暴露代理对象:
Spring通过singletonFactories获取BeanA的代理工厂,生成代理对象并注入BeanB。此时BeanB持有的BeanA是代理对象,而非原始对象。 - 完成初始化:
BeanA和BeanB最终完成初始化,代理对象在后续调用中拦截方法并执行切面逻辑。
5.3 关键验证:代理的提前生成
通过ProxyCreationTimingCase的日志可以看到,循环依赖中的Bean在@PostConstruct执行时已被代理:
[ProxyCreationTimingBeanC] 注入BeanD - 代理类型:class com.dwl.advisor_aspect.ProxyCreationTimingBeanD$$EnhancerBySpringCGLIB$$...
这说明Spring在循环依赖中提前生成了代理对象,确保依赖注入的是代理而非原始对象。
六、总结与扩展
6.1 总结
Spring AOP的底层原理可概括为以下核心步骤:
- 切面注册:编程式切面通过
DefaultPointcutAdvisor手动注册,注解式切面通过AnnotationAwareAspectJAutoProxyCreator自动转换为InstantiationModelAwarePointcutAdvisor。 - 切点匹配:
AspectJExpressionPointcut解析切点表达式,通过类过滤和方法匹配判断Advisor是否适用于目标类。 - 代理生成:
wrapIfNecessary方法根据切点匹配结果,选择JDK或CGLIB生成代理对象,并构建拦截器链。 - 通知执行:拦截器链按顺序执行通知逻辑(
@Around→@Before→目标方法→@AfterReturning/@AfterThrowing→@After)。
6.2 扩展学习方向
- 源码调试:通过IDE调试
AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization方法,观察代理生成的完整调用链。 - 性能优化:分析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内部的代理生成决策逻辑是否符合预期(如切面匹配规则、代理生成条件)。
*/