Spring的AOP:从使用到源码原理进行全解析 前言 在软件开发中,我们经常遇到这样的场景:需要在多个模块中记录日志、处理事务、检查权限。这些功能虽然与核心业务无关,却散布在代码的各个角落,造成大量重复代码。面向切面编程(AOP)正是为了解决这个问题而生。
Spring AOP作为Spring框架的核心模块之一,它通过动态代理技术,让我们能够将那些横切关注点(cross-cutting concerns)与业务逻辑分离,实现高内聚、低解耦的代码结构。
本文将带你从使用方式 出发,逐步深入到源码层面 ,全面解析Spring AOP的实现原理。我们会详细分析Spring如何创建代理对象、如何匹配增强器、如何执行拦截器链,并结合源码片段 和流程图 ,让你真正理解Spring AOP的每一个环节。
第一部分:AOP实战入门 1.1 从一个痛点开始 想象一下,你正在开发一个电商系统,需要在每个业务方法执行时记录日志、监控性能、检查权限。最直接的方式是在每个方法中编写重复代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class OrderService { public Order createOrder (Long userId, Long productId) { log.info("创建订单开始,参数:userId={}, productId={}" , userId, productId); checkPermission(userId); long start = System.currentTimeMillis(); try { Order order = doCreateOrder(userId, productId); long cost = System.currentTimeMillis() - start; log.info("创建订单完成,耗时:{}ms" , cost); return order; } catch (Exception e) { log.error("创建订单异常" , e); throw e; } } }
如果几十个业务类都这样写,代码重复率高达60%以上,维护成本极高。AOP的出现,就是为了解决这个问题。
1.2 Spring AOP快速上手 1.2.1 环境配置 在Spring Boot项目中,只需引入一个starter:
1 2 3 4 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
无需额外配置,Spring Boot会自动启用AOP功能。
1.2.2 核心注解详解 Spring AOP提供了五个核心注解,对应五种通知类型
注解
通知类型
执行时机
@Before
前置通知
目标方法执行前
@After
后置通知
目标方法执行后(无论是否异常)
@AfterReturning
返回通知
目标方法正常返回后
@AfterThrowing
异常通知
目标方法抛出异常后
@Around
环绕通知
包围目标方法,可控制执行时机
1.2.3 完整示例:日志切面 让我们通过一个完整的日志切面,快速掌握AOP的使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 @Component @Aspect public class LogAspect { @Pointcut("execution(* com.example.service.*.*(..))") public void serviceMethods () {} @Before("serviceMethods()") public void logBefore (JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); System.out.printf("[前置通知] 方法:%s,参数:%s%n" , methodName, Arrays.toString(args)); } @After("serviceMethods()") public void logAfter (JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.printf("[后置通知] 方法:%s 执行完毕%n" , methodName); } @AfterReturning(pointcut = "serviceMethods()", returning = "result") public void logAfterReturning (JoinPoint joinPoint, Object result) { String methodName = joinPoint.getSignature().getName(); System.out.printf("[返回通知] 方法:%s,返回值:%s%n" , methodName, result); } @AfterThrowing(pointcut = "serviceMethods()", throwing = "ex") public void logAfterThrowing (JoinPoint joinPoint, Exception ex) { String methodName = joinPoint.getSignature().getName(); System.out.printf("[异常通知] 方法:%s,异常:%s%n" , methodName, ex.getMessage()); } @Around("serviceMethods()") public Object logAround (ProceedingJoinPoint pjp) throws Throwable { long start = System.currentTimeMillis(); try { Object result = pjp.proceed(); long cost = System.currentTimeMillis() - start; System.out.printf("[环绕通知] 方法:%s,耗时:%dms%n" , pjp.getSignature().getName(), cost); return result; } catch (Exception e) { System.out.printf("[环绕通知] 方法:%s 异常:%s%n" , pjp.getSignature().getName(), e.getMessage()); throw e; } } }
1.2.4 切点表达式详解 切点表达式是AOP的核心,它决定了哪些方法会被拦截。常用的表达式类型如下:
1. execution:方法执行切点(最常用)
1 2 3 4 5 6 7 8 @Pointcut("execution(* com.example.service.*.*(..))") @Pointcut("execution(public * com.example.service.UserService.*(..))") @Pointcut("execution(* com.example.service.OrderService.createOrder(Long, String))")
2. within:类型匹配
1 2 3 4 5 @Pointcut("within(com.example.service.*)") @Pointcut("within(com.example.service.UserService)")
3. @annotation:注解匹配
1 2 @Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
4. args:参数匹配
1 2 @Pointcut("args(Long,..)")
1.2.5 ProceedingJoinPoint的妙用 在环绕通知中,ProceedingJoinPoint是核心对象,它提供了控制目标方法执行的能力:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Around("@annotation(cacheable)") public Object cache (ProceedingJoinPoint pjp, Cacheable cacheable) throws Throwable { String key = generateKey(pjp.getArgs()); Object value = redisTemplate.opsForValue().get(key); if (value != null ) { return value; } Object result = pjp.proceed(); redisTemplate.opsForValue().set(key, result, cacheable.ttl(), TimeUnit.SECONDS); return result; }
1.3 实战案例:权限控制切面 来看一个电商系统中典型的权限控制切面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 @Component @Aspect public class PermissionAspect { @Autowired private HttpServletRequest request; @Autowired private PermissionService permissionService; @Around("@annotation(permission)") public Object checkPermission (ProceedingJoinPoint pjp, Permission permission) throws Throwable { String token = request.getHeader("Authorization" ); Long userId = JwtUtils.getUserId(token); String[] requiredPermissions = permission.value(); boolean hasPermission = permissionService.checkPermissions(userId, requiredPermissions); if (!hasPermission) { throw new BusinessException ("无权限访问" ); } return pjp.proceed(); } }@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Permission { String[] value(); }@RestController public class OrderController { @PostMapping("/order/delete") @Permission({"order:delete", "admin"}) public Result deleteOrder (@RequestParam Long orderId) { return Result.success(); } }
第二部分:AOP核心概念与理论基础 2.1 AOP核心术语解析 在深入源码之前,我们需要彻底理解AOP的几个核心概念:
术语
含义
代码中的体现
切面(Aspect)
封装横切关注点的模块
被@Aspect注解的类
连接点(Joinpoint)
程序执行过程中的可插入点
主要是方法调用
切点(Pointcut)
定义哪些连接点会被拦截
@Pointcut表达式
通知(Advice)
切面在特定连接点执行的操作
@Before等方法
目标对象(Target)
被切面拦截的原始对象
业务类实例
代理对象(Proxy)
为目标对象创建的代理实例
JDK/CGLIB代理对象
织入(Weaving)
将切面应用到目标对象的过程
创建代理对象的过程
2.2 代理模式:AOP的基石 Spring AOP的本质是代理模式的应用。让我们先从静态代理入手,理解代理模式的核心思想。
2.2.1 静态代理:简单直观但不够灵活 以房屋交易为例,中介代理业主完成房屋交易:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 public interface HouseSubject { void saleHouse () ; void rentHouse () ; }public class RealHouseSubject implements HouseSubject { @Override public void saleHouse () { System.out.println("业主执行房屋出售流程:签订合同 → 办理过户" ); } @Override public void rentHouse () { System.out.println("业主执行房屋租赁流程:签订租约 → 交付房屋" ); } }public class HouseProxy implements HouseSubject { private HouseSubject realSubject; public HouseProxy (HouseSubject realSubject) { this .realSubject = realSubject; } @Override public void saleHouse () { System.out.println("[中介] 审核房屋产权证明 → 评估市场价格" ); realSubject.saleHouse(); System.out.println("[中介] 协助办理水电过户 → 交易归档" ); } @Override public void rentHouse () { System.out.println("[中介] 核实租客身份 → 签订租赁担保协议" ); realSubject.rentHouse(); System.out.println("[中介] 每月房屋状况巡检" ); } }
静态代理的优缺点 :
优点 :简单直观,易于理解
缺点 :
增强逻辑硬编码在代理类中
每个业务类都需要一个代理类,导致类爆炸
业务方法增减时,代理类必须同步修改
2.2.2 JDK动态代理:基于接口的代理 JDK动态代理是Java原生支持的代理机制,它要求目标类必须实现至少一个接口 。
核心组件:
Proxy类:动态生成代理类
InvocationHandler接口:定义增强逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 public class JdkDynamicProxyExample { interface UserService { void addUser (String name) ; } static class UserServiceImpl implements UserService { @Override public void addUser (String name) { System.out.println("添加用户:" + name); } } static class LogInvocationHandler implements InvocationHandler { private final Object target; public LogInvocationHandler (Object target) { this .target = target; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { System.out.println("[JDK代理] 方法执行前:" + method.getName()); Object result = method.invoke(target, args); System.out.println("[JDK代理] 方法执行后:" + method.getName()); return result; } } public static void main (String[] args) { UserService target = new UserServiceImpl (); UserService proxy = (UserService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new LogInvocationHandler (target) ); proxy.addUser("张三" ); } }
JDK动态代理的核心流程 :
Proxy.newProxyInstance()动态生成代理类字节码
代理类实现目标接口,所有方法调用转发给InvocationHandler
InvocationHandler.invoke()执行增强逻辑,通过反射调用目标方法
2.2.3 CGLIB动态代理:基于继承的代理 CGLIB(Code Generation Library)通过继承目标类 来创建代理,适合没有接口的类。
核心组件:
Enhancer类:生成代理类
MethodInterceptor接口:定义增强逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class CglibProxyExample { static class OrderService { public void createOrder (String product) { System.out.println("创建订单:" + product); } } static class LogMethodInterceptor implements MethodInterceptor { @Override public Object intercept (Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("[CGLIB代理] 方法执行前:" + method.getName()); Object result = proxy.invokeSuper(obj, args); System.out.println("[CGLIB代理] 方法执行后:" + method.getName()); return result; } } public static void main (String[] args) { Enhancer enhancer = new Enhancer (); enhancer.setSuperclass(OrderService.class); enhancer.setCallback(new LogMethodInterceptor ()); OrderService proxy = (OrderService) enhancer.create(); proxy.createOrder("iPhone" ); } }
CGLIB代理的核心流程 :
Enhancer设置父类为目标类
动态生成目标类的子类,重写所有非final方法
方法调用转发给MethodInterceptor.intercept()
intercept()中通过MethodProxy.invokeSuper()调用父类方法
2.2.4 两种代理方式对比
对比维度
JDK动态代理
CGLIB代理
原理
基于接口,实现相同接口
基于继承,生成子类
对目标类的要求
必须实现接口
无接口限制
性能
创建代理较快,调用稍慢
创建代理较慢,调用较快
限制
只能代理接口方法
不能代理final方法和final类
Spring Boot 2.x默认
仅当目标类没有接口时使用
默认开启,优先使用
2.3 Spring AOP与AspectJ的关系 Spring AOP和AspectJ是两个经常被混淆的概念:
Spring AOP :基于动态代理的运行时织入,是Spring框架的一部分,只能代理方法级别的拦截
AspectJ :完整的AOP框架,支持编译时、编译后、加载时织入,可以拦截字段访问、构造方法等更细粒度的连接点
Spring AOP借用了AspectJ的注解风格 (如@Aspect、@Before等),但底层实现仍是基于动态代理。
第三部分:源码深度解析 - 代理对象的创建 理解了理论基础后,我们进入源码分析环节。Spring AOP的核心流程可以分为三大步:
触发机制 :在Bean初始化后判断是否需要创建代理
匹配增强器 :查找适用于当前Bean的切面
创建代理对象 :选择JDK或CGLIB生成代理
我们以Spring Boot自动配置方式为例,基于Spring 5.3.x 源码进行分析。
3.1 触发机制:从后处理器开始 Spring AOP的入口是一个BeanPostProcessor——AnnotationAwareAspectJAutoProxyCreator。它会在Bean初始化完成后,检查是否需要为该Bean创建代理。
3.1.1 如何启用AOP 在纯Spring项目中,我们需要通过@EnableAspectJAutoProxy注解或XML配置<aop:aspectj-autoproxy/>来显式开启AOP功能。
1 2 3 4 5 @Configuration @EnableAspectJAutoProxy public class JiangAppConfig { }
@EnableAspectJAutoProxy注解的源码如下:
1 2 3 4 5 6 7 8 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { boolean proxyTargetClass () default false ; boolean exposeProxy () default false ; }
3.1.2 AspectJAutoProxyRegistrar注册后处理器 AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,负责向容器中注册AOP后处理器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions (AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAspectJAutoProxy != null ) { if (enableAspectJAutoProxy.getBoolean("proxyTargetClass" )) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } if (enableAspectJAutoProxy.getBoolean("exposeProxy" )) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } } }
最终注册到容器中的是AnnotationAwareAspectJAutoProxyCreator,它继承自AbstractAutoProxyCreator,而后者实现了BeanPostProcessor接口。因此,Spring容器在启动时会将这个后处理器实例化,并在每个Bean初始化后自动调用其postProcessAfterInitialization方法。
3.1.3 AbstractAutoProxyCreator的核心方法 AbstractAutoProxyCreator作为骨架类,定义了代理创建的核心流程。其关键字段如下:
字段
类型
作用
earlyProxyReferences
Map<Object, Object>
存储早期代理引用,Key为Bean的缓存键(通常是BeanName或Bean实例的标识),Value为原始Bean。用于解决循环依赖:当Bean正在创建且被提前暴露时,记录该引用,避免重复创建代理。
targetSourcedBeans
Set<String>
记录已经通过自定义TargetSource创建了代理的Bean名称。如果Bean已经通过TargetSource代理,则后续不再处理。
advisedBeans
Map<Object, Boolean>
缓存Bean是否需要被代理的结果。Key为Bean的缓存键,Value为Boolean:TRUE表示需要代理,FALSE表示不需要。用于避免重复判断,提升性能。
proxyTypes
Map<Object, Class<?>>
缓存代理对象的类型,Key为Bean的缓存键,Value为代理对象的Class。用于快速获取代理类型。
proxyClassLoader
ClassLoader
代理类的类加载器,默认为beanClassLoader。
使用时机 :
earlyProxyReferences 在getEarlyBeanReference方法中填充,用于提前暴露代理以解决循环依赖。
advisedBeans 在wrapIfNecessary中查询和设置,避免重复解析切面。
targetSourcedBeans 在createProxy后添加,标记已通过自定义TargetSource创建代理。
关键方法是postProcessAfterInitialization,它在Bean初始化后被调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Override public Object postProcessAfterInitialization (@Nullable Object bean, String beanName) { if (bean != null ) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this .earlyProxyReferences.remove(cacheKey) != bean) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
wrapIfNecessary方法是整个AOP代理创建的入口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 protected Object wrapIfNecessary (Object bean, String beanName, Object cacheKey) { if (StringUtils.hasLength(beanName) && this .targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this .advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this .advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } Object[] specificInterceptors = getAdvicesAndAdvisorsForBean( bean.getClass(), beanName, null ); if (specificInterceptors != DO_NOT_PROXY) { this .advisedBeans.put(cacheKey, Boolean.TRUE); Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource (bean)); this .proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this .advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
3.2 匹配增强器:查找适用的切面 获取适用增强器的方法是getAdvicesAndAdvisorsForBean,它在AbstractAdvisorAutoProxyCreator中实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 @Override @Nullable protected Object[] getAdvicesAndAdvisorsForBean( Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); }protected List<Advisor> findEligibleAdvisors (Class<?> beanClass, String beanName) { List<Advisor> candidateAdvisors = findCandidateAdvisors(); List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply( candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }
3.2.1 查找候选Advisor findCandidateAdvisors在AnnotationAwareAspectJAutoProxyCreator中被重写,目标是为了获取到所有的Advisors。
Advisor是Spring AOP中最基本的接口,它包含一个Advice(增强逻辑)。常见的实现类有InstantiationModelAwarePointcutAdvisorImpl(用于AspectJ注解方式)和DefaultPointcutAdvisor(编程式使用)。
InstantiationModelAwarePointcutAdvisorImpl 字段:
字段
类型
作用
pointcut
Pointcut
切点定义,用于匹配连接点。
advice
Advice
真正的增强逻辑,可能是MethodBeforeAdvice、AspectJAfterAdvice等。
aspectName
String
所属切面Bean的名称。
declarationOrder
int
在切面类中的声明顺序,用于排序。
isBeforeAdvice
boolean
缓存是否为前置通知。
isAfterAdvice
boolean
缓存是否为后置通知。
isLazy
boolean
标记是否懒加载切面实例。
DefaultPointcutAdvisor 字段:
字段
类型
作用
pointcut
Pointcut
切点,默认为TruePointcut.INSTANCE(匹配所有方法)。
advice
Advice
增强逻辑。
order
int
排序顺序,可通过setOrder设置。
该方法会扫描所有@Aspect注解的类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @Override protected List<Advisor> findCandidateAdvisors () { List<Advisor> advisors = super .findCandidateAdvisors(); if (this .aspectJAdvisorsBuilder != null ) { advisors.addAll(this .aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }public List<Advisor> buildAspectJAdvisors () { String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( beanFactory, Object.class, true , false ); for (String beanName : beanNames) { Class<?> beanType = beanFactory.getType(beanName); if (beanType == null ) continue ; if (this .advisorFactory.isAspect(beanType)) { List<Advisor> classAdvisors = this .advisorFactory.getAdvisors(getAspectInstanceFactory(beanName)); advisors.addAll(classAdvisors); } } return advisors; }
一个@Aspect类如何被解析成多个Advisor :
1 2 3 4 5 6 7 8 9 10 11 12 13 @Aspect @Component public class LogAspect { @Before("execution(* com..*.*(..))") public void before () { ... } @After("execution(* com..*.*(..))") public void after () { ... } @Around("execution(* com..*.*(..))") public Object around () { ... } }
以上切面类会被解析成3个Advisor,每个Advisor包含:
Pointcut :从表达式解析而来
Advice :封装了通知方法的信息
优先级 :根据@Order注解或方法名排序
3.2.2 筛选可应用的Advisor findAdvisorsThatCanApply方法负责筛选出能应用于当前Bean的Advisor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 protected List<Advisor> findAdvisorsThatCanApply ( List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName); try { return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { ProxyCreationContext.setCurrentProxiedBeanName(null ); } }public static List<Advisor> findAdvisorsThatCanApply ( List<Advisor> advisors, Class<?> clazz) { if (advisors.isEmpty()) { return advisors; } List<Advisor> eligibleAdvisors = new ArrayList <>(); for (Advisor advisor : advisors) { if (canApply(advisor, clazz)) { eligibleAdvisors.add(advisor); } } return eligibleAdvisors; }public static boolean canApply (Advisor advisor, Class<?> targetClass) { if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pca = (PointcutAdvisor) advisor; return canApply(pca.getPointcut(), targetClass); } return true ; }public static boolean canApply (Pointcut pc, Class<?> targetClass) { if (!pc.getClassFilter().matches(targetClass)) { return false ; } Method[] methods = ReflectionUtils.getAllDeclaredMethods(targetClass); for (Method method : methods) { if (pc.getMethodMatcher().matches(method, targetClass)) { return true ; } } return false ; }
这里的核心逻辑是:判断切点表达式是否能匹配目标类的任何一个方法 。只要有一个方法匹配,这个Advisor就适用于当前Bean。
3.2.3 Advisor的排序 多个Advisor的执行顺序很重要,Spring通过sortAdvisors方法进行排序:
1 2 3 4 5 6 7 8 9 10 11 protected List<Advisor> sortAdvisors (List<Advisor> advisors) { AnnotationAwareOrderComparator.sort(advisors); return advisors; }
排序规则总结 :
优先级数值越小的越先执行
相同优先级的,执行顺序由切面类中通知方法的定义顺序决定
@Around > @Before > @After > @AfterReturning/@AfterThrowing(在同一个切面内)
3.3 创建代理对象 当确定了需要代理的Bean和适用的Advisor后,createProxy方法负责实际创建代理对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 protected Object createProxy (Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { ProxyFactory proxyFactory = new ProxyFactory (); proxyFactory.copyFrom(this ); if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true ); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } } Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this .freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true ); } return proxyFactory.getProxy(getProxyClassLoader()); }
3.3.1 ProxyFactory的核心配置 ProxyFactory是创建代理的核心类,它继承自ProxyCreatorSupport,后者又继承自AdvisedSupport。AdvisedSupport包含了创建代理所需的所有配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class AdvisedSupport extends ProxyConfig implements Advised { private TargetSource targetSource; private List<Advisor> advisors = new ArrayList <>(); private Class<?>[] interfaces; }public class ProxyConfig implements Serializable { private boolean proxyTargetClass = false ; private boolean optimize = false ; private boolean opaque = false ; private boolean exposeProxy = false ; private boolean frozen = false ; }
3.3.2 代理方式的选择策略 getProxy方法最终调用createAopProxy创建代理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 protected final synchronized AopProxy createAopProxy () { if (!this .active) { activate(); } return getAopProxyFactory().createAopProxy(this ); }public class DefaultAopProxyFactory implements AopProxyFactory , Serializable { @Override public AopProxy createAopProxy (AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null ) { throw new AopConfigException ("..." ); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy (config); } return new ObjenesisCglibAopProxy (config); } else { return new JdkDynamicAopProxy (config); } } private boolean hasNoUserSuppliedProxyInterfaces (AdvisedSupport config) { Class<?>[] ifcs = config.getProxiedInterfaces(); return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0 ]))); } }
3.3.3 JdkDynamicAopProxy源码分析 JdkDynamicAopProxy实现了InvocationHandler和AopProxy接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 final class JdkDynamicAopProxy implements AopProxy , InvocationHandler, Serializable { private final AdvisedSupport advised; public JdkDynamicAopProxy (AdvisedSupport config) throws AopConfigException { this .advised = config; } @Override public Object getProxy () { return getProxy(ClassUtils.getDefaultClassLoader()); } @Override public Object getProxy (@Nullable ClassLoader classLoader) { Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this .advised, true ); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this ); } @Override @Nullable public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { Object oldProxy = null ; boolean setProxyContext = false ; TargetSource targetSource = this .advised.targetSource; Object target = null ; try { if (!this .equalsDefined && AopUtils.isEqualsMethod(method)) { return equals(args[0 ]); } if (!this .hashCodeDefined && AopUtils.isHashCodeMethod(method)) { return hashCode(); } if (method.getDeclaringClass() == DecoratingProxy.class) { return AopProxyUtils.ultimateTargetClass(this .advised); } if (!this .advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { return AopUtils.invokeJoinpointUsingReflection(this .advised, method, args); } Object retVal; if (this .advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true ; } target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null ); List<Object> chain = this .advised.getInterceptorsAndDynamicInterceptionAdvice( method, targetClass); if (chain.isEmpty()) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { MethodInvocation invocation = new ReflectiveMethodInvocation ( proxy, target, method, args, targetClass, chain); retVal = invocation.proceed(); } Class<?> returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { retVal = proxy; } return retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } } }
3.3.4 CglibAopProxy源码分析 CglibAopProxy使用CGLIB的Enhancer创建代理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 class CglibAopProxy implements AopProxy , Serializable { private final AdvisedSupport advised; @Override public Object getProxy () { return getProxy(null ); } @Override public Object getProxy (@Nullable ClassLoader classLoader) { Class<?> rootClass = this .advised.getTargetClass(); Enhancer enhancer = new Enhancer (); if (classLoader != null ) { enhancer.setClassLoader(classLoader); } Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this .advised, true ); enhancer.setInterfaces(proxiedInterfaces); enhancer.setSuperclass(rootClass); enhancer.setInterceptDuringConstruction(false ); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy (classLoader)); Callback[] callbacks = getCallbacks(rootClass); enhancer.setCallbacks(callbacks); enhancer.setCallbackFilter(new ProxyCallbackFilter (this .advised)); return createProxyClassAndInstance(enhancer, callbacks); } private static class DynamicAdvisedInterceptor implements MethodInterceptor , Serializable { private final AdvisedSupport advised; @Override @Nullable public Object intercept (Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null ; boolean setProxyContext = false ; Object target = null ; TargetSource targetSource = this .advised.getTargetSource(); try { if (this .advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true ; } target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null ); List<Object> chain = this .advised.getInterceptorsAndDynamicInterceptionAdvice( method, targetClass); Object retVal; if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { retVal = methodProxy.invoke(target, args); } else { MethodInvocation invocation = new CglibMethodInvocation ( proxy, target, method, args, targetClass, chain, methodProxy); retVal = invocation.proceed(); } Class<?> returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { retVal = proxy; } return retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } } } }
第四部分:源码深度解析 - 代理的执行 代理对象创建完成后,当调用代理对象的方法时,拦截器链如何执行?这是AOP的核心执行机制。
4.1 拦截器链的获取 在invoke方法中,通过getInterceptorsAndDynamicInterceptionAdvice获取拦截器链:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 public List<Object> getInterceptorsAndDynamicInterceptionAdvice ( Method method, @Nullable Class<?> targetClass) { MethodCacheKey cacheKey = new MethodCacheKey (method); List<Object> cached = this .methodCache.get(cacheKey); if (cached == null ) { cached = this .advisorAdapterRegistry.getInterceptorsAndDynamicInterceptionAdvice( this , method, targetClass); this .methodCache.put(cacheKey, cached); } return cached; }public List<Object> getInterceptorsAndDynamicInterceptionAdvice ( Advised config, Method method, @Nullable Class<?> targetClass) { List<Object> interceptorList = new ArrayList <>(config.getAdvisors().length); Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); for (Advisor advisor : config.getAdvisors()) { if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass) && pointcutAdvisor.getPointcut().getMethodMatcher().matches(method, actualClass)) { MethodInterceptor[] interceptors = registry.getInterceptors(advisor); for (MethodInterceptor interceptor : interceptors) { interceptorList.add(interceptor); } } } else if (advisor instanceof IntroductionAdvisor) { if (config.isPreFiltered() || ((IntroductionAdvisor) advisor).getClassFilter().matches(actualClass)) { MethodInterceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { MethodInterceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }
关键点 :AdvisorAdapterRegistry负责将不同类型的Advice适配为MethodInterceptor。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List<MethodInterceptor> interceptors = new ArrayList <>(3 ); Advice advice = advisor.getAdvice(); if (advice instanceof MethodInterceptor) { interceptors.add((MethodInterceptor) advice); } for (AdvisorAdapter adapter : this .adapters) { if (adapter.supportsAdvice(advice)) { interceptors.add(adapter.getInterceptor(advisor)); } } if (interceptors.isEmpty()) { throw new UnknownAdviceTypeException (advisor.getAdvice()); } return interceptors.toArray(new MethodInterceptor [0 ]); }
pring内置了三个适配器,分别对应@Before、@AfterReturning、@AfterThrowing(注意@Around本身就是MethodInterceptor):
MethodBeforeAdviceAdapter:将MethodBeforeAdvice适配为MethodInterceptor
AfterReturningAdviceAdapter:将AfterReturningAdvice适配为MethodInterceptor
ThrowsAdviceAdapter:将ThrowsAdvice适配为MethodInterceptor
4.2 ReflectiveMethodInvocation的proceed方法 当有了拦截器链后,ReflectiveMethodInvocation负责按顺序执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public class ReflectiveMethodInvocation implements ProxyMethodInvocation , Cloneable { protected final Object proxy; protected final Object target; protected final Method method; protected Object[] arguments; private final Class<?> targetClass; private List<Object> interceptorsAndDynamicMethodMatchers; private int currentInterceptorIndex = -1 ; @Override @Nullable public Object proceed () throws Throwable { if (this .currentInterceptorIndex == this .interceptorsAndDynamicMethodMatchers.size() - 1 ) { return invokeJoinpoint(); } Object interceptorOrInterceptionAdvice = this .interceptorsAndDynamicMethodMatchers.get(++this .currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this .method, this .targetClass, this .arguments)) { return dm.interceptor.invoke(this ); } else { return proceed(); } } else { return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this ); } } @Nullable protected Object invokeJoinpoint () throws Throwable { return AopUtils.invokeJoinpointUsingReflection(this .target, this .method, this .arguments); } }
核心机制 :这是一个递归+索引 的执行模式。
currentInterceptorIndex从-1开始
每次proceed()将索引+1,获取下一个拦截器
拦截器内部调用invocation.proceed()继续执行下一个
最后一个拦截器执行完后,调用目标方法
4.3 拦截器执行流程剖析 让我们通过一个具体例子,理解拦截器链的执行流程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Aspect public class LogAspect { @Before("execution(* *.*(..))") public void before () { System.out.println("before" ); } @After("execution(* *.*(..))") public void after () { System.out.println("after" ); } @Around("execution(* *.*(..))") public Object around (ProceedingJoinPoint pjp) throws Throwable { System.out.println("around start" ); Object result = pjp.proceed(); System.out.println("around end" ); return result; } }
当调用代理对象的方法时,拦截器链的执行顺序如下:
关键点说明 :
@Around包裹了整个执行过程,可以控制proceed()的调用
@Before在目标方法前执行
@After通过try-finally机制保证在目标方法后执行
多个拦截器通过递归链式调用
4.4 不同类型通知的拦截器实现 4.4.1 AspectJAroundAdvice(环绕通知) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor { @Override public Object invoke (MethodInvocation mi) throws Throwable { if (!(mi instanceof ProxyMethodInvocation)) { throw new IllegalStateException ("..." ); } ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi; ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi); try { return invokeAdviceMethod(pjp, null , null ); } catch (Throwable t) { throw t; } } }
4.4.2 MethodBeforeAdviceInterceptor(前置通知) 1 2 3 4 5 6 7 8 9 10 11 12 13 public class MethodBeforeAdviceInterceptor implements MethodInterceptor , BeforeAdvice, Serializable { private final MethodBeforeAdvice advice; @Override public Object invoke (MethodInvocation mi) throws Throwable { this .advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()); return mi.proceed(); } }
4.4.3 AfterReturningAdviceInterceptor(返回通知) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class AfterReturningAdviceInterceptor implements MethodInterceptor , AfterAdvice, Serializable { private final AfterReturningAdvice advice; @Override public Object invoke (MethodInvocation mi) throws Throwable { Object retVal = mi.proceed(); this .advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); return retVal; } }
4.4.5 AspectJAfterThrowingAdvice(异常通知) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice implements MethodInterceptor , AfterAdvice { @Override public Object invoke (MethodInvocation mi) throws Throwable { try { return mi.proceed(); } catch (Throwable t) { if (shouldInvokeOnThrowing(t)) { invokeAdviceMethod(getJoinPointMatch(), null , t); } throw t; } } }
4.5 拦截器执行顺序总结 综合上述源码分析,我们可以得出拦截器的执行顺序:
1 2 3 4 5 6 7 8 9 10 11 12 13 try { return result; } catch (Exception e) { throw e; } finally { }
多个切面的执行顺序 :
切面优先级:@Order(1) < @Order(2)(值越小优先级越高)
同一优先级:按切面类名排序(不可控)
同一切面内:@Around → @Before → @After → @AfterReturning/@AfterThrowing
第五部分:常见问题 5.1 同一个类内部方法调用的问题 这是一个经典的AOP陷阱:同一个类中的方法调用不会触发AOP增强。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Service public class UserService { @Transactional public void methodA () { System.out.println("methodA" ); } public void methodB () { this .methodA(); } }
原因分析 :
Spring AOP基于代理,外部调用通过代理对象进入
this.methodA()调用的是目标对象本身,不是代理对象
代理逻辑无法被触发
解决方案 :
重构代码(推荐)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Service public class UserService { @Transactional public void methodA () { ... } }@Service public class AnotherService { @Autowired private UserService userService; public void methodB () { userService.methodA(); } }
自我注入(需要Spring 5+)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Service public class UserService { @Autowired @Lazy private UserService self; @Transactional public void methodA () { ... } public void methodB () { self.methodA(); } }
使用AopContext获取当前代理
1 2 3 4 5 6 7 8 9 10 11 @Service public class UserService { @Transactional public void methodA () { ... } public void methodB () { ((UserService) AopContext.currentProxy()).methodA(); } }
5.2 代理方式的选择策略 Spring Boot 2.x开始,默认使用CGLIB代理。可以通过配置调整:
1 2 3 spring: aop: proxy-target-class: false
选择建议 :
JDK动态代理 :目标类有完善的接口设计,追求更清晰的抽象
CGLIB代理 :无接口的类,或需要代理所有方法(包括非接口方法)
结语 通过本文的源码分析,我们完整地走通了Spring AOP的创建 和执行 两大核心流程:
代理创建流程 :
@EnableAspectJAutoProxy注册AnnotationAwareAspectJAutoProxyCreator
postProcessAfterInitialization触发代理创建
wrapIfNecessary判断是否需要代理
getAdvicesAndAdvisorsForBean查找匹配的增强器
createProxy根据配置选择JDK或CGLIB生成代理
代理执行流程 :
代理对象方法调用进入invoke/intercept
获取匹配当前方法的拦截器链
ReflectiveMethodInvocation递归执行拦截器
各种Advice按顺序执行其增强逻辑
最终调用目标方法并返回结果
理解这些原理,不仅能帮助我们更好地使用AOP,还能在遇到问题时快速定位并解决。希望本文能对你深入理解Spring AOP有所帮助。