一. 前置知识 1 动态代理 1.1 JDK动态代理
基于接口的动态代理机制。它允许在运行时动态创建实现接口的代理类,并通过代理类来控制对目标对象的访问
核心在于代理类会将所有方法调用转发给 InvocationHandler.invoke
方法,从而可以在方法调用前后插入自定义逻辑。
核心组件
InvocationHandler 接口 :用来定义代理对象的方法拦截逻辑。
1 Object invoke (Object proxy, Method method, Object[] args) throws Throwable;
1 2 3 - proxy : 代理对象 - method:被调用的真实方法 - args: 方法参数
Proxy 类 :用来生成动态代理类。
1 static Object newProxyInstance (ClassLoader loader, Class<?>[]
1 2 3 - loader:类加载器,通常是目标类的类加载器 - interfaces: 被代理对象(目标对象)实现的接口数组 - h: InvocationHandler 实例
使用示例
示例一 添加用户
定义接口
1 2 3 public interface UserService { String addUser () ; }
实现类
1 2 3 4 5 6 7 class UserServiceImpl implements UserService { @Override public String addUser () { System.out.println("adduser running..." ); return "adduser successfully" ; } }
代理拦截逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class UserServiceProxy implements InvocationHandler { private final Object target; public UserServiceProxy (Object target) { this .target = target; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before addUser" ); Object invoke = method.invoke(target, args); System.out.println("after addUser" ); return invoke; } }
测试
1 2 3 4 5 6 7 class UserServiceProxyTest { public static void main (String[] args) { UserService target = new UserServiceImpl (); UserService userService = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class []{UserService.class}, new UserServiceProxy (target)); System.out.println(userService.addUser()); } }
输出
1 2 3 4 before addUser adduser running... after addUser adduser successfully
示例二 Mybatis Mapper接口代理
以UserMapper为例
接口
1 2 3 public interface UserMapper { User getUserById (String id) ; }
代理工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class MapperProxyFactory { private final Class<?> mapperInterface = UserMapper.class; protected UserMapper newInstance (MapperProxy mapperProxy) { return (UserMapper) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class [] { mapperInterface }, mapperProxy); } public UserMapper newInstance () { final MapperProxy mapperProxy = new MapperProxy (mapperInterface); return newInstance(mapperProxy); } }
代理逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class MapperProxy implements InvocationHandler { private final Class<?> mapperInterface; public MapperProxy (Class<?> mapperInterface) { this .mapperInterface = mapperInterface; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { System.out.println("执行代理方法" ); return user } }
测试
1 2 3 4 5 6 7 8 public class Test { public static void main (String[] args) { MapperProxyFactory mapperProxyFactory = new MapperProxyFactory (); UserMapper userMapper = mapperProxyFactory.newInstance(); User userById = userMapper.getUserById("1" ); System.out.println(userById); } }
1.2 CGLIB动态代理
1.用来代理 没有实现接口的类。
2.CGLIB 动态代理基于字节码操作,通过继承目标类并重写其方法的方式实现代理。代理类在运行时生成,实际调用时会将方法调用委托给 MethodInterceptor 。
核心组件
Enhancer
net.sf.cglib.proxy.Enhancer 核心类用来生成代理对象
配置被代理类及拦截器后,调用 create()
方法生成代理对象
MethodInterceptor
1 Object intercept (Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable;
- obj: 代理对象
- method: 被调用的真实方法
- args : 方法参数
- proxy : 用于调用目标类方法的 `MethodProxy` 对象。 由CGLIB生成,提供了对目标方法的直接访问,可以避免反射带来的性能损耗。
使用示例
示例 以添加用户为例
定义目标类(需要代理的类)
1 2 3 4 5 public class UserService { public void addUser (String name) { System.out.println("Adding user: " + name); } }
创建MethodInterceptor(方法拦截器)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class UserServiceMethodInterceptor implements MethodInterceptor { private final Object target; public UserServiceMethodInterceptor (Object target) { this .target = target; } @Override public Object intercept (Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("Before method: " + method.getName()); Object result = methodProxy.invoke(target, objects); System.out.println("After method: " + method.getName()); return result; } }
使用 Enhancer 创建代理对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class CGLIBProxyExample { public static void main (String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Enhancer enhancer = new Enhancer (); UserService target = new UserService (); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(new UserServiceMethodInterceptor (target)); UserService proxy = (UserService) enhancer.create(); Method method = target.getClass().getMethod("addUser" , String.class); String result = (String) method.invoke(proxy, "Alice" ); System.out.println(result); } }
输出
1 2 3 4 Before method: addUser Adding user running: Alice After method: addUser addUser success
CGLIB单独使用需要引入相关依赖
1 2 3 4 5 <dependency > <groupId > cglib</groupId > <artifactId > cglib</artifactId > <version > 3.3.0</version > </dependency >
1.3 CGLIB 动态代理与 JDK 动态代理对比
特性
CGLIB 动态代理
JDK 动态代理
代理目标
任何类(不需要实现接口)
必须实现接口
原理
字节码生成(基于 ASM)
反射机制
性能
较高(直接操作字节码)
较低(通过反射调用)
对 final
限制
无法代理 final
类或方法
无限制
性能对比
CGLIB 性能优于 JDK 动态代理 :
JDK 动态代理依赖反射调用,性能较低。
CGLIB 直接生成字节码,调用开销小。
但生成代理类时间较长 :
CGLIB 在第一次创建代理对象时,需要生成代理类字节码,消耗时间较多。
2 Spring ProxyFactory
简化了代理对象的创建过程,并集成了 Spring 的 AOP 功能。利用 ProxyFactory
可以更方便地创建动态代理,同时享受 Spring 提供的更多功能。
使用示例 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 import org.springframework.aop.MethodBeforeAdvice;import org.springframework.aop.framework.Advised;import org.springframework.aop.framework.ProxyFactory;import java.lang.reflect.Method;public interface UserService { void addUser (String name) ; } class UserServiceImpl implements UserService { @Override public void addUser (String name) { System.out.println("Adding user: " + name); } } class BeforeAdvice implements MethodBeforeAdvice { @Override public void before (Method method, Object[] args, Object target) throws Throwable { System.out.println("Before method: " + method.getName()); } } class ProxyFactoryExample { public static void main (String[] args) { UserService target = new UserServiceImpl (); ProxyFactory proxyFactory = new ProxyFactory (); proxyFactory.setTarget(target); proxyFactory.setInterfaces(UserService.class); proxyFactory.addAdvice(new BeforeAdvice ()); proxyFactory.setExposeProxy(true ); proxyFactory.setFrozen(true ); UserService proxy = (UserService) proxyFactory.getProxy(); proxy.addUser("Alice" ); System.out.println(b); } }
Spring Aop主要时通过这个类创建代理对象 ,在创建对象时会根据传入的目标类或者接口决定使用哪种动态代理
如果是CGLB 会使用 CglibAopProxy 创建代理对象
如果是JDK 会使用 JdkDynamicAopProxy 创建代理对象 继承关系图
两者都实现了AopProxy
1 2 3 4 5 6 7 8 9 10 public interface AopProxy { Object getProxy () ; Object getProxy (@Nullable ClassLoader classLoader) ; }
在 Spring 框架中,面向切面编程(AOP) 通过 @Aspect
注解来定义切面(Aspect),以实现横切关注点(如日志记录、事务管理、权限校验等)的模块化。@Aspect
AOP 的实现贯穿于 Spring 容器的生命周期中,主要依赖于 Bean 后处理器(BeanPostProcessor) 和 代理机制 。本文将详细介绍 @Aspect
AOP 在 Spring 生命周期中的具体实现位置及其工作原理。
二. Spring AOP 概述 面向切面编程(AOP) 允许开发者将横切关注点(Cross-Cutting Concerns)从业务逻辑中分离出来,以提高代码的模块化和可维护性。Spring AOP 提供了基于代理的 AOP 实现,支持使用 @Aspect
注解定义切面。
1. 主要概念
切面(Aspect) :模块化的横切关注点,例如日志记录、事务管理。
连接点(Join Point) :程序执行的特定点,如方法调用。
通知(Advice) :在连接点执行的动作,如前置通知、后置通知。
切点(Pointcut) :定义通知应用的连接点。
织入(Weaving) :将切面应用到目标对象的过程,通常通过代理实现。
2. Spring 容器生命周期简介 Spring 容器的生命周期主要包括以下几个阶段:
加载 Bean 定义 :解析配置文件或注解,加载 Bean 的定义信息。
实例化 Bean :创建 Bean 的实例。
填充 Bean 属性 :注入依赖(依赖注入)。
初始化 Bean :调用初始化方法(如 @PostConstruct
注解的方法)。
使用 Bean :应用程序使用 Bean。
销毁 Bean :容器关闭时,销毁 Bean。
其中在实例化,初始化过程中都可以**应用 Bean 后处理器(BeanPostProcessor)**:对 Bean 进行进一步处理,如代理创建(初始化后前)。
3. 工作流程 以下是 @Aspect AOP 在 Spring 容器生命周期中的详细工作流程:
扫描与注册切面 :
Spring 扫描到被 @Aspect
注解标记的类,并将其注册为切面 Bean。
实例化切面 Bean :
**应用 AnnotationAwareAspectJAutoProxyCreator
**:
作为一个 BeanPostProcessor,AnnotationAwareAspectJAutoProxyCreator
会在目标 Bean 创建后检查是否需要为其创建代理。
解析切点与通知 :
AnnotationAwareAspectJAutoProxyCreator
解析切面的切点表达式,确定哪些目标 Bean 的哪些方法需要被拦截。
创建代理对象 :
对于符合条件的目标 Bean,ProxyFactory
会创建代理对象,并将通知(Advice)织入其中。
选择代理方式:
JDK 动态代理 :如果目标 Bean 实现了至少一个接口,默认使用 JDK 动态代理。
CGLIB 代理 :如果目标 Bean 没有实现接口,或者强制要求使用 CGLIB 代理,则使用 CGLIB。
初始化与使用 :
代理对象完成后,Spring 继续完成 Bean 的初始化过程。
应用程序在使用 Bean 时,实际上操作的是代理对象,从而实现了 AOP 织入的功能。
4. 流程原理解析 4.1. Advisor接口
Advisor 是一个结合了 Pointcut(切入点) 和 Advice(通知) 的对象。它定义了特定的切入点以及在这些切入点上执行的具体通知逻辑。通过 Advisor,AOP 框架能够在运行时动态地将横切关注点应用到目标对象的合适位置。
4.2. AnnotationAwareAspectJAutoProxyCreator
这是 Spring AOP 的核心组件之一 ,Bean后置处理器 ,负责自动创建代理对象。其主要职责包括:
扫描解析切面类 :识别被 @Aspect
注解标记的类。 ——- 实例化前阶段
解析切点表达式 :通过 @Pointcut
或切点表达式,定义哪些方法会被切面通知所拦截。
创建代理 :为符合切点条件的 Bean 创建代理对象,并将通知织入其中。 ——— 初始化后阶段
4.2.1. 扫描解析切面类
实例化前阶段会解析切面类
AbstractAutoProxyCreator#postProcessBeforeInstantiation
1 2 3 4 5 6 7 8 9 10 11 12 13 public Object postProcessBeforeInstantiation (Class<?> beanClass, String beanName) { Object cacheKey = getCacheKey(beanClass, beanName); if (!StringUtils.hasLength(beanName) || !this .targetSourcedBeans.contains(beanName)) { if (this .advisedBeans.containsKey(cacheKey)) { return null ; } if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this .advisedBeans.put(cacheKey, Boolean.FALSE); return null ; } } }
往下跟进
AspectJAwareAdvisorAutoProxyCreator#shouldSkip
1 2 3 4 5 6 7 8 9 10 11 12 @Override protected boolean shouldSkip (Class<?> beanClass, String beanName) { List<Advisor> candidateAdvisors = findCandidateAdvisors(); for (Advisor advisor : candidateAdvisors) { if (advisor instanceof AspectJPointcutAdvisor && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) { return true ; } } return super .shouldSkip(beanClass, beanName); }
跟进
AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors 方法
1 2 3 4 5 6 7 8 9 10 @Override protected List<Advisor> findCandidateAdvisors () { List<Advisor> advisors = super .findCandidateAdvisors(); if (this .aspectJAdvisorsBuilder != null ) { advisors.addAll(this .aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }
super.findCandidateAdvisors()
: 调用父类的方法加载事务相关的Advisor
buildAspectJAdvisors()
: 解析切面类
跟进
BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
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 public List<Advisor> buildAspectJAdvisors () { List<String> aspectNames = this .aspectBeanNames; if (aspectNames == null ) { synchronized (this ) { aspectNames = this .aspectBeanNames; if (aspectNames == null ) { List<Advisor> advisors = new ArrayList <>(); aspectNames = new ArrayList <>(); String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this .beanFactory, Object.class, true , false ); for (String beanName : beanNames) { if (!isEligibleBean(beanName)) { continue ; } Class<?> beanType = this .beanFactory.getType(beanName, false ); if (beanType == null ) { continue ; } if (this .advisorFactory.isAspect(beanType)) { aspectNames.add(beanName); AspectMetadata amd = new AspectMetadata (beanType, beanName); if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory (this .beanFactory, beanName); List<Advisor> classAdvisors = this .advisorFactory.getAdvisors(factory); if (this .beanFactory.isSingleton(beanName)) { this .advisorsCache.put(beanName, classAdvisors); } else { this .aspectFactoryCache.put(beanName, factory); } advisors.addAll(classAdvisors); } else { if (this .beanFactory.isSingleton(beanName)) { throw new IllegalArgumentException ("Bean with name '" + beanName + "' is a singleton, but aspect instantiation model is not singleton" ); } MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory (this .beanFactory, beanName); this .aspectFactoryCache.put(beanName, factory); advisors.addAll(this .advisorFactory.getAdvisors(factory)); } } } this .aspectBeanNames = aspectNames; return advisors; } } } if (aspectNames.isEmpty()) { return Collections.emptyList(); } List<Advisor> advisors = new ArrayList <>(); for (String aspectName : aspectNames) { List<Advisor> cachedAdvisors = this .advisorsCache.get(aspectName); if (cachedAdvisors != null ) { advisors.addAll(cachedAdvisors); } else { MetadataAwareAspectInstanceFactory factory = this .aspectFactoryCache.get(aspectName); advisors.addAll(this .advisorFactory.getAdvisors(factory)); } } return advisors; }
跟进
ReflectiveAspectJAdvisorFactory#getAdvisors
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 public List<Advisor> getAdvisors (MetadataAwareAspectInstanceFactory aspectInstanceFactory) { Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName(); validate(aspectClass); MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator (aspectInstanceFactory); List<Advisor> advisors = new ArrayList <>(); for (Method method : getAdvisorMethods(aspectClass)) { Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0 , aspectName); if (advisor != null ) { advisors.add(advisor); } } if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor (lazySingletonAspectInstanceFactory); advisors.add(0 , instantiationAdvisor); } for (Field field : aspectClass.getDeclaredFields()) { Advisor advisor = getDeclareParentsAdvisor(field); if (advisor != null ) { advisors.add(advisor); } } return advisors; } private List<Method> getAdvisorMethods (Class<?> aspectClass) { List<Method> methods = new ArrayList <>(); ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter); if (methods.size() > 1 ) { methods.sort(adviceMethodComparator); } return methods; } @Override @Nullable public Advisor getAdvisor (Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) { validate(aspectInstanceFactory.getAspectMetadata().getAspectClass()); AspectJExpressionPointcut expressionPointcut = getPointcut( candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass()); if (expressionPointcut == null ) { return null ; } return new InstantiationModelAwarePointcutAdvisorImpl (expressionPointcut, candidateAdviceMethod, this , aspectInstanceFactory, declarationOrderInAspect, aspectName); }
有关排序Spring官方解释
==所有的方法按照Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class)排序, 尽管@After在@AfterReturn和@AfterThrowing之前排序,但@After通知方法实际上会在@AfterReturning和@AfterThrowing方法之后被调用, 因为在“try”块中调用invokes proceed(),而“finally”块中只调用@After注解的通知==
跟进 InstantiationModelAwarePointcutAdvisorImpl
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 public InstantiationModelAwarePointcutAdvisorImpl (AspectJExpressionPointcut declaredPointcut, Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { this .declaredPointcut = declaredPointcut; this .declaringClass = aspectJAdviceMethod.getDeclaringClass(); this .methodName = aspectJAdviceMethod.getName(); this .parameterTypes = aspectJAdviceMethod.getParameterTypes(); this .aspectJAdviceMethod = aspectJAdviceMethod; this .aspectJAdvisorFactory = aspectJAdvisorFactory; this .aspectInstanceFactory = aspectInstanceFactory; this .declarationOrder = declarationOrder; this .aspectName = aspectName; if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { Pointcut preInstantiationPointcut = Pointcuts.union( aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this .declaredPointcut); this .pointcut = new PerTargetInstantiationModelPointcut ( this .declaredPointcut, preInstantiationPointcut, aspectInstanceFactory); this .lazy = true ; } else { this .pointcut = this .declaredPointcut; this .lazy = false ; this .instantiatedAdvice = instantiateAdvice(this .declaredPointcut); } } private Advice instantiateAdvice (AspectJExpressionPointcut pointcut) { Advice advice = this .aspectJAdvisorFactory.getAdvice(this .aspectJAdviceMethod, pointcut, this .aspectInstanceFactory, this .declarationOrder, this .aspectName); return (advice != null ? advice : EMPTY_ADVICE); }
跟进 ReflectiveAspectJAdvisorFactory#getAdvice
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 106 107 108 109 110 111 112 113 114 115 public Advice getAdvice (Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); validate(candidateAspectClass); AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if (aspectJAnnotation == null ) { return null ; } if (!isAspect(candidateAspectClass)) { throw new AopConfigException ("Advice must be declared inside an aspect type: " + "Offending method '" + candidateAdviceMethod + "' in class [" + candidateAspectClass.getName() + "]" ); } if (logger.isDebugEnabled()) { logger.debug("Found AspectJ method: " + candidateAdviceMethod); } AbstractAspectJAdvice springAdvice; switch (aspectJAnnotation.getAnnotationType()) { case AtPointcut: if (logger.isDebugEnabled()) { logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'" ); } return null ; case AtAround: springAdvice = new AspectJAroundAdvice ( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break ; case AtBefore: springAdvice = new AspectJMethodBeforeAdvice ( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break ; case AtAfter: springAdvice = new AspectJAfterAdvice ( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break ; case AtAfterReturning: springAdvice = new AspectJAfterReturningAdvice ( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterReturningAnnotation.returning())) { springAdvice.setReturningName(afterReturningAnnotation.returning()); } break ; case AtAfterThrowing: springAdvice = new AspectJAfterThrowingAdvice ( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterThrowingAnnotation.throwing())) { springAdvice.setThrowingName(afterThrowingAnnotation.throwing()); } break ; default : throw new UnsupportedOperationException ( "Unsupported advice type on method: " + candidateAdviceMethod); } springAdvice.setAspectName(aspectName); springAdvice.setDeclarationOrder(declarationOrder); String[] argNames = this .parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); if (argNames != null ) { springAdvice.setArgumentNamesFromStringArray(argNames); } springAdvice.calculateArgumentBindings(); return springAdvice; } public final synchronized void calculateArgumentBindings () { if (this .argumentsIntrospected || this .parameterTypes.length == 0 ) { return ; } int numUnboundArgs = this .parameterTypes.length; Class<?>[] parameterTypes = this .aspectJAdviceMethod.getParameterTypes(); if (maybeBindJoinPoint(parameterTypes[0 ]) || maybeBindProceedingJoinPoint(parameterTypes[0 ]) || maybeBindJoinPointStaticPart(parameterTypes[0 ])) { numUnboundArgs--; } if (numUnboundArgs > 0 ) { bindArgumentsByName(numUnboundArgs); } this .argumentsIntrospected = true ; } private boolean maybeBindProceedingJoinPoint (Class<?> candidateParameterType) { if (ProceedingJoinPoint.class == candidateParameterType) { if (!supportsProceedingJoinPoint()) { throw new IllegalArgumentException ("ProceedingJoinPoint is only supported for around advice" ); } this .joinPointArgumentIndex = 0 ; return true ; } else { return false ; } }
4.2.2. 解析切点,创建代理对象
初始化后阶段,会根据解析出来的通知匹配,从而创建代理对象
AbstractAutoProxyCreator#postProcessAfterInitialization
1 2 3 4 5 6 7 8 9 10 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
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 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; }
isInfrastructureClass :和切面有关(切面类,切面接口实现类)的都不会被代理
shouldSkip : 如果advisor是AspectJPointcutAdvisor实例且当前的类的bean名称和切面名称相等也不会被代理
跟进
AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
1 2 3 4 5 6 7 8 9 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(); }
findEligibleAdvisors
1 2 3 4 5 6 7 8 9 10 11 12 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; }
findAdvisorsThatCanApply
1 2 3 4 5 6 7 8 9 10 11 protected List<Advisor> findAdvisorsThatCanApply ( List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName); try { return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { ProxyCreationContext.setCurrentProxiedBeanName(null ); } }
AopUtils#findAdvisorsThatCanApply
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 public static List<Advisor> findAdvisorsThatCanApply (List<Advisor> candidateAdvisors, Class<?> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } List<Advisor> eligibleAdvisors = new ArrayList <>(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor) { continue ; } if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; }
AopUtils#canApply
判断给定的 切点 (Pointcut
)是否可以应用于目标类(targetClass
)上
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 public static boolean canApply (Advisor advisor, Class<?> targetClass, boolean hasIntroductions) { if (advisor instanceof IntroductionAdvisor) { return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); } else if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pca = (PointcutAdvisor) advisor; return canApply(pca.getPointcut(), targetClass, hasIntroductions); } else { return true ; } } public static boolean canApply (Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { Assert.notNull(pc, "Pointcut must not be null" ); if (!pc.getClassFilter().matches(targetClass)) { return false ; } MethodMatcher methodMatcher = pc.getMethodMatcher(); if (methodMatcher == MethodMatcher.TRUE) { return true ; } IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null ; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; } Set<Class<?>> classes = new LinkedHashSet <>(); if (!Proxy.isProxyClass(targetClass)) { classes.add(ClassUtils.getUserClass(targetClass)); } classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); for (Class<?> clazz : classes) { Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz); for (Method method : methods) { if (introductionAwareMethodMatcher != null ? introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) : methodMatcher.matches(method, targetClass)) { return true ; } } } return false ; } private ShadowMatch getShadowMatch (Method targetMethod, Method originalMethod) { ShadowMatch shadowMatch = this .shadowMatchCache.get(targetMethod); if (shadowMatch == null ) { shadowMatch = obtainPointcutExpression().matchesMethodExecution(methodToMatch); this .shadowMatchCache.put(targetMethod, shadowMatch); } return shadowMatch; }
createProxy
用于创建代理对象
AbstractAutoProxyCreator#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 42 43 44 protected Object createProxy (Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { ProxyFactory proxyFactory = new ProxyFactory (); proxyFactory.copyFrom(this ); if (proxyFactory.isProxyTargetClass()) { if (Proxy.isProxyClass(beanClass)) { for (Class<?> ifc : beanClass.getInterfaces()) { proxyFactory.addInterface(ifc); } } } else { 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 ); } ClassLoader classLoader = getProxyClassLoader(); if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) { classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader(); } return proxyFactory.getProxy(classLoader); }
5. 实战示例 定义切面类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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 @Slf4j @Aspect @Component public class CustomAspect { @Before("@annotation(com.yang.demoservice.aop.Log)") public void beforeAroundDemo (JoinPoint joinPoint) { log.info("4.CustomAspect#before--aroundDemo方法执行前--" + joinPoint.getSignature()); } @Around(value = "execution(* com.yang.demoservice.controller.DemoController.aroundDemo(..))&&args(name,age)", argNames = "joinPoint,name,age") public Object aroundAroundDemoArgs (ProceedingJoinPoint joinPoint, String name, Integer age) throws Throwable { log.info("2.CustomAspect#aroundAroundDemoArgs--环绕通知--aroundDemo方法执行前" ); log.info("2.CustomAspect#aroundAroundDemoArgs--方法参数,name:{},参数2,age:{}" , name, age); Object proceed = joinPoint.proceed(); log.info("9.CustomAspect#aroundAroundDemoArgs--环绕通知--aroundDemo方法执行后" ); return proceed; } @Around("@annotation(rel)") public Object aroundAroundDemoLog (ProceedingJoinPoint joinPoint, Log rel) throws Throwable { log.info("3.CustomAspect#aroundAroundDemoLog--环绕通知--aroundDemo方法执行前" ); log.info("3.CustomAspect#aroundAroundDemoLog--注解参数,log.value:{}" , rel.value()); Object proceed = joinPoint.proceed(); log.info("8.CustomAspect#aroundAroundDemoLog--注解参数,环绕通知--aroundDemo方法执行后" ); return proceed; } @After("@annotation(com.yang.demoservice.aop.Log)) ") public void afterAroundDemo(JoinPoint joinPoint) { log.info(" 7. CustomAspect#after--aroundDemo方法执行后--" + joinPoint.getSignature()); } /** * 方法正常执行完成 返回通知 */ @AfterReturning(value = " @annotation(com.yang.demoservice.aop.Log) ", returning = " result") public void afterReturningAroundDemo(JoinPoint joinPoint, String result) { log.info(" 6. CustomAspect#afterReturning--aroundDemo方法正常执行完成--" + joinPoint.getSignature()); log.info(" 6. CustomAspect#afterReturning--aroundDemo方法执行返回值:" + result); } /** * 方法执行异常 异常通知 */ @AfterThrowing(value = " @annotation(com.yang.demoservice.aop.Log) ", throwing = " ex") public void afterThrowingAroundDemo(JoinPoint joinPoint, Exception ex) { log.info(" --CustomAspect#afterThrowing--aroundDemo方法执行异常--" + joinPoint.getSignature()); log.info(" --CustomAspect#afterThrowing--aroundDemo异常信息--" + ex); } //------------------------------------------------------------------------------
定义切面类2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Slf4j @Aspect @Component public class Custom2Aspect { @Pointcut("@annotation(com.yang.demoservice.aop.Log)") public void pointCut () { } @Before("pointCut()") public void before (JoinPoint joinPoint) { log.info("1.Custom2Aspect#before--aroundDemo方法执行前--" +joinPoint.getSignature()); } }
controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Slf4j @RestController @RequestMapping("/demo") public class DemoController { @Log("环绕通知") @RequestMapping("/d2") public String aroundDemo (String name, Integer age) { if (StrUtil.isNotBlank(name) && age != null ) { String result = name + ":" + age; log.info("5.aroundDemo:" + result + "执行成功" ); return "aroundDemo" + result; } else { log.info("5.aroundDemo:" + "执行失败" ); throw new RuntimeException ("aroundDemo" + "执行失败" ); } } }
切面类1和切面类2 所有通知都作用于同一连接点
没抛出异常
访问 : http://localhost:8099/demo/d2?name=zhangsan&age=20
输出结果
抛出异常
访问 : http://localhost:8099/demo/d2
输出结果
结论:
在同一个切面类 CustomAspect
没有抛出异常:通知的执行顺序是 Around, Before, AfterReturning, After
抛出异常: 通知的执行顺序是 Around, Before, AfterThrowing, After
为什么Custom2Aspect内的切面类中的before会优先执行呢?
在项目结构里面Custom2Aspect排在在CustomAspect前面,所以Spring在解析时会优先解析Custom2Aspect,可以通过@Order注解控制顺序
如果没指定Spring在解析bean时会按照文件排列顺序依次往下解析,由于Custom2Aspect优先被解析,所以Custom2Aspect内的通知优先被执行
在不同切面类中,可以通过@Order控制通知顺序
6. 关于切点表达式 SpringAop中文文档
7. 总结 在 Spring Boot 应用中,@Aspect
AOP 的实现紧密集成于 Spring 容器的生命周期,主要通过 Bean 后处理器(BeanPostProcessor) 和 代理机制 来完成。具体来说,AnnotationAwareAspectJAutoProxyCreator
作为一个重要的 BeanPostProcessor,负责扫描切面类、解析切点表达式,并为符合条件的目标 Bean 创建代理对象,将切面的通知织入其中。