本文主要是介绍Spring源码解析(九):AOP源码之@Aspect所有相关注解解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Spring源码系列文章
Spring源码解析(一):环境搭建
Spring源码解析(二):bean容器的创建、默认后置处理器、扫描包路径bean
Spring源码解析(三):bean容器的刷新
Spring源码解析(四):单例bean的创建流程
Spring源码解析(五):循环依赖
Spring源码解析(六):bean工厂后置处理器ConfigurationClassPostProcessor
Spring源码解析(七):bean后置处理器AutowiredAnnotationBeanPostProcessor
Spring源码解析(八):bean后置处理器CommonAnnotationBeanPostProcessor
Spring源码解析(九):AOP源码之@Aspect所有相关注解解析
Spring源码解析(十):spring整合mybatis源码
Spring源码解析(十一):spring事务配置类源码
Spring源码解析(十二):TransactionInterceptor事务拦截器
目录
- 一、AOP简介
- 二、AnnotationAwareAspectJAutoProxyCreator的注册
- 三、postProcessBeforeInstantiation(实例化前寻找增强器并缓存)
- 1、isInfrastructureClass是否AspectJ基础类
- 2、shouldSkip是否跳过bean
- 2.1、findCandidateAdvisors查找增强器
- 总结
- 四、getEarlyBeanReference(循环依赖,提前暴露 bean)
- 五、postProcessAfterInitialization(初始化后创建代理对象)
- 1、wrapIfNecessary(包装目标类,如果需要的话)
- 1.1、获取当前Bean的所有增强器
- 1.2、创建代理对象
- createAopProxy
- getProxy(jdk代理)
- 1.3、处理器的invoke方法
- 获取拦截器链
- 执行拦截器链
- 拦截器链顺序
- 2、各种拦截器作用
- 2.1、ExposeInvocationInterceptor默认拦截器
- 2.2、AspectJAroundAdvice环绕通知拦截器
- MethodInvocationProceedingJoinPoint类图
- argBinding绑定参数
- 反射执行通知方法
- 通知方法的执行顺序
- 2.3、MethodBeforeAdviceInterceptor前置通知拦截器
- 2.4、AspectJAfterAdvice后置(最终)通知拦截器
- 2.4、AspectJAfterAdvice返回通知拦截器
- 2.5、AspectJAfterThrowingAdvice异常通知拦截器
- 3、总结通知执行顺序
一、AOP简介
- AOP是一种思想,它的实现主要有
Spring AOP
和AspectJ
- spring AOP底层实现是jdk和cglib动态代理
- 运行期织入
- 借助了AspectJ的语法,即使用了@Aspect @Before @Pointcut等注解来实现
- AspectJ主要原理是用asm做字节码替换来达到AOP的目的,需要使用专门的编译器
ajc
- 编译期、编译期后、类加载期都可以织入
AnnotationAwareAspectJAutoProxyCreator主要类图
- AOP的操作流程都在
AnnotationAwareAspectJAutoProxyCreator
类中 - 添加
@EnableAspectJAutoProxy
注解由@Import注解导入而来
- 实现BeanPostProcessor、InstantiationAwareBeanPostProcessor等bean后置处理器
- 查看AbstractAutoProxyCreator结构
- 获取提前暴露bean方法(创建并返回代理对象)
实例化前
寻找增强器并缓存初始化后
创建代理对象
二、AnnotationAwareAspectJAutoProxyCreator的注册
配置类
@Configuration
@ComponentScan(value = "com.xc")
/*** Spring AOP 默认使用 JDK 动态代理** proxyTargetClass = true 时则代理目标对象时强制使用 CGLIB 代理* @see DefaultAopProxyFactory#createAopProxy(org.springframework.aop.framework.AdvisedSupport)** exposeProxy = true 暴露代理对象,这样就可以使用 AopContext.currentProxy() 方法获取当前代理的对象* @see AopContext#currentProxy* @see JdkDynamicAopProxy#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])** 可以解决在方法里面调方法,或者用 this 关键字调方法,而无法被代理的情况**/
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
public class AopConfig {}
@EnableAspectJAutoProxy注解
- 这个注解上面导入了一个
AspectJAutoProxyRegistrar
类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {boolean proxyTargetClass() default false;boolean exposeProxy() default false;
}
- 它实现了ImportBeanDefinitionRegistrar,通过registerBeanDefinitions()方法
注册bean 定义
- 注册
AnnotationAwareAspectJAutoProxyCreator.class
,名称为“org.springframework.aop.config.internalAutoProxyCreator” - 如果我们设置EnableAspectJAutoProxy的两个属性,那么也将其注入BeanDefinition中
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {// 注册AspectJ相关的处理组件AnnotationAwareAspectJAutoProxyCreatorAopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);// 为组件AnnotationAwareAspectJAutoProxyCreator添加属性AnnotationAttributes enableAspectJAutoProxy =AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);if (enableAspectJAutoProxy != null) {if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);}}}
}
注册核心类的方法栈
三、postProcessBeforeInstantiation(实例化前寻找增强器并缓存)
- advisedBeans:map集合,key表示bean
名称
value表示bean是否需要被代理
- 如果一个bean的方法需要增强,那么这个 bean 就需要被代理来实现
- this.advisedBeans.put(cacheKey, Boolean.TRUE);(后面操作)
注解切面类
和切面接口相关类
Advice、Pointcut、Advisor、AopInfrastructureBean,不需要被代理- this.advisedBeans.put(cacheKey, Boolean.FALSE); (当前方法目的1)
- 如果一个bean的方法需要增强,那么这个 bean 就需要被代理来实现
- 将切面类所有的通知方法封装为Advisor增强器,缓存起来(当前方法目的2)
- 判断该类是否值自定义加强类型getCustomTargetSource(一般没有)
- 若是则加强执行包装操作返回代理对象
private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);...// 这个方法的主要目的就是在不考虑通知的情况下,确认哪些Bean不需要被代理
// 1.Advice,Advisor,Pointcut类型的Bean不需要被代理
// 2.不是原始Bean被包装过的Bean不需要被代理,例如ScopedProxyFactoryBean
// 实际上并不只是这些Bean不需要被代理,如果没有对应的通知需要被应用到这个Bean上的话
// 这个Bean也是不需要被代理的,只不过不是在这个方法中处理的。
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {Object cacheKey = getCacheKey(beanClass, beanName);// 如果beanName为空 或 没有为这个bean提供了定制的targetSourceif (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {// advisedBeans是一个map,其中key是BeanName,value代表了这个Bean是否需要被代理// 如果已经包含了这个key,不需要在进行判断了,直接返回即可// 因为这个方法的目的就是在实例化前就确认哪些Bean是不需要进行AOP的if (this.advisedBeans.containsKey(cacheKey)) {return null;}// 说明还没有对这个Bean进行处理// 在这里会对SpringAOP中的基础设施bean,例如Advice,Pointcut,Advisor做标记// 标志它们不需要被代理,对应的就是将其放入到advisedBeans中,value设置为false// 其次,如果这个Bean不是最原始的Bean,那么也不进行代理,也将其value设置为falseif (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return null;}}// 是否为这个Bean提供了定制的TargetSource// 如果提供了定制的TargetSource,那么直接在这一步创建一个代理对象并返回// 一般不会提供TargetSource targetSource = getCustomTargetSource(beanClass, beanName);if (targetSource != null) {if (StringUtils.hasLength(beanName)) {this.targetSourcedBeans.add(beanName);}Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}return null;
}
1、isInfrastructureClass是否AspectJ基础类
- 子类重写父类方法isInfrastructureClass,又调用了父类方法
- 父类与子类方法满足其中一个即返回true,是AspectJ基础类
- 父类:当前 bean是否切面相关的类
Advice
、Pointcut
、Advisor
、AopInfrastructureBean
- 平常使用的注解,也可以使用接口实现
- 子类:当前 bean 是否切面(@Aspect注解的 bean)
- 父类:当前 bean是否切面相关的类
// 父类AbstractAutoProxyCreator方法
protected boolean isInfrastructureClass(Class<?> beanClass) {boolean retVal = Advice.class.isAssignableFrom(beanClass) ||Pointcut.class.isAssignableFrom(beanClass) ||Advisor.class.isAssignableFrom(beanClass) ||AopInfrastructureBean.class.isAssignableFrom(beanClass);return retVal;
}
// 子类AnnotationAwareAspectJAutoProxyCreator方法
@Override
protected boolean isInfrastructureClass(Class<?> beanClass) {return (super.isInfrastructureClass(beanClass) ||(this.aspectJAdvisorFactory != null &&this.aspectJAdvisorFactory.isAspect(beanClass)));
}
- @Aspect注解切面 bean 的判断
- 当前 bean 有
@Aspect
注解,并且没有使用ajc
编译器
// AbstractAspectJAdvisorFactory类的方法
@Override
public boolean isAspect(Class<?> clazz) {return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}// 当前 bean 是否找到注解Aspect
private boolean hasAspectAnnotation(Class<?> clazz) {return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}// 当前 bean 的属性值名字是否ajc$,就是判断是否使用 ajc 编译器
private boolean compiledByAjc(Class<?> clazz) {for (Field field : clazz.getDeclaredFields()) {if (field.getName().startsWith(AJC_MAGIC)) {return true;}}return false;
}
2、shouldSkip是否跳过bean
- 看名字很简单,以为只是简单的判断
- 点进方法也简单,实际和上个方法逻辑一样,子类重写父类方法(主要逻辑在重写方法中)
- 先走子类方法,然后子类中调用父类的简单逻辑方法
// 子类AspectJAwareAdvisorAutoProxyCreator方法
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {// 查找所有候选的通知List<Advisor> candidateAdvisors = findCandidateAdvisors();for (Advisor advisor : candidateAdvisors) {/*** 是 AspectJPointcutAdvisor 的子类 并且 切面名称是 beanName* 一般是 InstantiationModelAwarePointcutAdvisorImpl**/if (advisor instanceof AspectJPointcutAdvisor &&((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {return true;}}return super.shouldSkip(beanClass, beanName);
}
- 父类方法:一般都是 false
- beanName的长度 = bean全限定类名+ .ORIGINAL(原始后缀)返回 true
// 父类AbstractAutoProxyCreator方法
protected boolean shouldSkip(Class<?> beanClass, String beanName) {return AutoProxyUtils.isOriginalInstance(beanName, beanClass);
}
2.1、findCandidateAdvisors查找增强器
- 老套路,先调用重写的子类,子类调用父类
// 子类AnnotationAwareAspectJAutoProxyCreator方法
@Override
protected List<Advisor> findCandidateAdvisors() {// 获取Advisor子类增强器List<Advisor> advisors = super.findCandidateAdvisors();// 获取带有@AspectJ注解增强器if (this.aspectJAdvisorsBuilder != null) {advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());}return advisors;
}
- 父类:把类型为Advisor的Bean都找出来处理,也就是通过接口实现AOP,我们一般使用注解,这里就是空
// 父类AbstractAdvisorAutoProxyCreator方法
protected List<Advisor> findCandidateAdvisors() {Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");return this.advisorRetrievalHelper.findAdvisorBeans();
}
buildAspectJAdvisors() 构建@AspectJ注解增强器
- 找到系统中使用
@Aspect
标注的bean - 并且找到该bean中使用
@Before
,@After
等标注的方法
- 将这些方法封装为一个个
Advisor
public List<Advisor> buildAspectJAdvisors() {// 因为解析会很消耗性能,所以 Spring 会使用 aspectBeanNames 保存解析结果List<String> aspectNames = this.aspectBeanNames;// 如果==null 代表没处理过,因为第二次肯定不为 null,在 进入这个条件后,就会创建 ArrayListif (aspectNames == null) {// 进行加锁处理,防止多线程情况下一起操作解析synchronized (this) {// 二次赋值,防治以及操作过了aspectNames = this.aspectBeanNames;//双重非空判断,避免再次解析if (aspectNames == null) {List<Advisor> advisors = new ArrayList<>();// 创建切面集合aspectNames = new ArrayList<>();// 查找所有的 BeanName 包括父类String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);for (String beanName : beanNames) {//排除不合法的ban,由子类定义规则,默认返回trueif (!isEligibleBean(beanName)) {continue;}// 根据Name获取Class类型Class<?> beanType = this.beanFactory.getType(beanName);if (beanType == null) {continue;}// 判断 是否存在 @Aspect 注解 并且判断 目标类上所有的属性不包含 "ajc$"if (this.advisorFactory.isAspect(beanType)) {// 将 切面的 BeanName 放入到集合中aspectNames.add(beanName);// 包装成 AspectMetadataAspectMetadata amd = new AspectMetadata(beanType, beanName);//检查 @Aspect 注解的value值,验证生成的增强是否是单例if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {// 创建一个工厂..MetadataAwareAspectInstanceFactory factory =new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);// 获取标记 Aspect 注解的增强方法List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);//如果bean是单例,则缓存bean的增强器if (this.beanFactory.isSingleton(beanName)) {// 将 切面 BeanName 和 增强器 进行缓存this.advisorsCache.put(beanName, classAdvisors);}// bean非单例,只缓存bean对应的增强器创建工厂else {this.aspectFactoryCache.put(beanName, factory);}// 将获取的 增强器 放入到集合中advisors.addAll(classAdvisors);}else {// 切面创建模式非单例,这里的Else 基本不会进来...// 如果切面是非单例,但是bean是单例,抛出异常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));}}}//将已经解析过的切面 Bean 进行缓存this.aspectBeanNames = aspectNames;return advisors;}}}// 如果是 null 就会直接返回...if (aspectNames.isEmpty()) {// 如果是一个空的就返回一个空集合return Collections.emptyList();}List<Advisor> advisors = new ArrayList<>();// 循环 切面的Namefor (String aspectName : aspectNames) {// 根据切面的Name 获取 增强器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;
}
advisorFactory.getAdvisors 获取所有增强器
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {// 目标Aspect类Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();// 代理对象Bean的nameString aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();// 校验Aspect类上是不是标注了@Aspect注解validate(aspectClass);// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator// so that it will only instantiate once.MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);List<Advisor> advisors = new ArrayList<>();//获取排除@Pointcut注解的其他方法for (Method method : getAdvisorMethods(aspectClass)) {//真正创建增强器Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);if (advisor != null) {advisors.add(advisor);}}// 通过在装饰者内部的开始加入SyntheticInstantiationAdvisor增强器,达到延迟初始化切面bean的目的if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);advisors.add(0, instantiationAdvisor);}// 对@DeclareParent注解功能的支持(引入)for (Field field : aspectClass.getDeclaredFields()) {Advisor advisor = getDeclareParentsAdvisor(field);if (advisor != null) {advisors.add(advisor);}}return advisors;
}
获取排除@Pointcut注解的其他方法并排序
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;
}
getAdvisor 获取单个增强器
- 可以看出 Advisor 指的就是
切入点
和通知方法
的汇总
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;}// 在创建 InstantiationModelAwarePointcutAdvisorImpl 的时候 // 里面有一个 instantiateAdvice--> getAdvice 比较重要需要看一下// 将切入点和通知包装成一个 增强器return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, //切入点表达式candidateAdviceMethod, //通知方法this,aspectInstanceFactory, // 切面实例的工厂..declarationOrderInAspect, //0aspectName //切面名称);
}
InstantiationModelAwarePointcutAdvisorImpl构造函数 创建具体通知
- 环绕通知增强器:AspectJAroundAdvice
- 实现
MethodInterceptor
接口,方法拦截器
- 实现
- 前置通知增强器:AspectJMethodBeforeAdvice
- 实现
MethodBeforeAdvice
接口,前置方法回调接口
- 实现
- 后置通知增强器:AspectJAfterAdvice
- 实现
MethodInterceptor
接口,方法拦截器
- 实现
- 返回通知增强器:AspectJAfterReturningAdvice
- 实现
AfterReturningAdvice
接口,前置方法回调接口 - 根据注解的属性值
returning
设置返回值参数名称
- 实现
- 异常通知增强器:AspectJAfterThrowingAdvice
- 实现
MethodInterceptor
接口,方法拦截器 - 根据注解的属性值
throwing
设置异常参数名称
- 实现
getAdvice() 生成不同通知实现类的方法
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {//切面类 带有@Aspect注解的类Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();validate(candidateAspectClass);// 获取通知方法的注解类型来确认当前方法是具体的那个类型的通知// @Pointcut @Around @Before @After.class @AfterReturning @AfterThrowingAspectJAnnotation<?> 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() + "]");}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;//如果是前置通知,则直接创建AspectJMethodBeforeAdvice实例//入参为:通知方法、切点表达式、切面实例case AtBefore:springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);break;//如果是后置通知,则直接创建AspectJAfterAdvice实例//入参为:通知方法、切点表达式、切面实例case AtAfter:springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);break;//如果是后置返回通知,则直接创建AspectJAfterReturningAdvice实例//入参为:通知方法、切点表达式、切面实例case AtAfterReturning:springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();//设置后置返回值的参数nameif (StringUtils.hasText(afterReturningAnnotation.returning())) {springAdvice.setReturningName(afterReturningAnnotation.returning());}break;//如果是后置异常通知,则直接创建AspectJAfterThrowingAdvice实例//入参为:通知方法、切点表达式、切面实例case AtAfterThrowing:springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();//设置后置异常通知 异常类型参数nameif (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);// 通知注解中的参数名,换而言之就是获取 通知注解中的 argNames 属性String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);if (argNames != null) {springAdvice.setArgumentNamesFromStringArray(argNames);}//计算argNames和类型的对应关系springAdvice.calculateArgumentBindings();return springAdvice;
}
总结
- 将不需要代理的切面类挑选出来
- 将切面的所有通知封装成增强器缓存起来
四、getEarlyBeanReference(循环依赖,提前暴露 bean)
- 如果出现循环依赖,需要提前暴露,这里创建代理对象并返回
- 将原始对象放入earlyProxyReferences,为了判断初始化后是否需要创建代理对象
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {Object cacheKey = getCacheKey(bean.getClass(), beanName);this.earlyProxyReferences.put(cacheKey, bean);return wrapIfNecessary(bean, beanName, cacheKey);
}
五、postProcessAfterInitialization(初始化后创建代理对象)
- earlyProxyReferences如果有值(证明已经创建代理对象),remove 返回删除的对象,if 条件不成立,不再创建代理对象
- earlyProxyReferences没值(没有创建代理对象),remove 返回 null,if 条件成立,创建代理对象
@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;
}
1、wrapIfNecessary(包装目标类,如果需要的话)
- advisedBeans这个map上面说过,key为bean名称,value为是否需要代理
- 如果当前bean的方法匹配任意切面任意通知,那么则此bean需要被代理
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {// 判断 beanName是正常的 并且 targetSourcedBeans已经存在则会直接返回(多例情况下)if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}//判断 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;}// Create proxy if we have advice.// 创建代理对象// 1. 获取当前Bean的所有增强器(通知方法)Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);// 如果不是 null 则会去生成代理对象,否则则标记当前类不需要进行代理.if (specificInterceptors != DO_NOT_PROXY) {// 将其放入到集合当中代表已经增强过了...this.advisedBeans.put(cacheKey, Boolean.TRUE);// 2. 创建代理Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));// 将数据进行缓存this.proxyTypes.put(cacheKey, proxy.getClass());// 返回代理对象...return proxy;}// 如果不需要代理则设置为 False 当下次进来的时候会直接返回this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;
}
1.1、获取当前Bean的所有增强器
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();
}
- findCandidateAdvisors():获取所有切面类所有的通知方法封装为Advisor的增强器
- 实例化前已经获取,这里从缓存中获取即可
- findAdvisorsThatCanApply():获取当前bean能够应用的增强器
- 根据增强器的Pointcut表达式匹配当前bean的方法
- extendAdvisors():如果在该Bean上存在切面,创建ExposeInvocationInterceptor拦截器
- ExposeInvocationInterceptor类实现MethodInterceptor接口,方法拦截器
- 通过ThreadLocal暴露MethodInterceptor,调用链环节中直接获取
- sortAdvisors:主要作用不同切面的通知排序
- @Order注解的value属性指定各个切面的执行顺序,value值默认为Integer的最大值,value越小优先级越高
- 若两个或多个切面通过@Order注解标注且value值相同则又会通过默认的按bean名称字母排序
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;
}
1.2、创建代理对象
代理工厂类图
创建代理工厂,添加创建代理需要的参数
- 代理的方式(jdk 或 cglib)
- 如果是jdk代理,添加需要实现的接口(目标对象实现的接口)
- 所有的增强器
- 目标对象
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource) {if (this.beanFactory instanceof ConfigurableListableBeanFactory) {AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);}//创建 代理工厂ProxyFactory proxyFactory = new ProxyFactory();// 将当前类的一些配置进行 复制 ,简单来说就是获取 XML 或者注解配置的属性proxyFactory.copyFrom(this);// 判断是否是通过接口 默认是 Falseif (!proxyFactory.isProxyTargetClass()) {// 根据最开始@EnableAspectJAutoProxy注解中的proxyTargetClass参数判断// 是否应该使用cglib代理(默认jdk代理)if (shouldProxyTargetClass(beanClass, beanName)) {//标识 使用cglib动态代理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());
}
代理对象生成分析
- 通过ProxyFactory根据相应属性创建代理对象,首先创建
AopProxy
- 根据bean是否继承接口,生成
ObjenesisCglibAopProxy
或者JdkDynamicAopProxy
- 根据bean是否继承接口,生成
- 然后
getProxy
获取代理对象
public Object getProxy(@Nullable ClassLoader classLoader) {// createAopProxy() 获取AOP 工厂判断 CGlib还是JDKreturn createAopProxy().getProxy(classLoader);
}
createAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {// 需要优化【默认为False】 或者 proxyTargetClass属性值为True【默认为False】 或者 没有用户提供的代理接口if (config.isOptimize() || config.isProxyTargetClass()|| hasNoUserSuppliedProxyInterfaces(config)) {// 目标类Class<?> targetClass = config.getTargetClass();if (targetClass == null) {throw new AopConfigException();}// 是接口 或者 类本身就是一个通过jdk动态代理生成的类if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {// 使用 JDK 动态代理return new JdkDynamicAopProxy(config);}// 使用 CGLIB 代理return new ObjenesisCglibAopProxy(config);}// 默认使用 JDK 动态代理else {return new JdkDynamicAopProxy(config);}
}
getProxy(jdk代理)
- Proxy.newProxyInstance(
classLoader
,proxiedInterfaces
,this
);- classLoader:类加载器
- proxiedInterfaces:代理对象需要实现的接口
- this:当前对象(其实是需要InvocationHandler的实现类,执行目标对象方法时,会触发它的的invoke方法)
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
...public Object getProxy(@Nullable ClassLoader classLoader) {if (logger.isDebugEnabled()) {logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());}// 这里获取到代理类需要实现的所有的接口Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);// 需要明确是否在接口定义了hashCode以及equals方法// 如果接口中没有定义,那么在调用代理对象的equals方法的时候// 如果两个对象相等,那么意味着它们的目标对象,通知以及实现的接口都相同findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);}
...
}
获取到需要实现的接口
- 目标对象实现的接口
SpringProxy
:标记接口,代表这个类是通过Spring的AOP代理生成的Advised
,提供了管理通知的方法DecoratingProxy
,用于获取到真实的目标对象
static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {// 第一步:获取在配置中指定的需要实现的接口Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();// 第二步:如果没有指定需要实现的接口,但是需要代理的目标类本身就是一个接口// 那么将其添加到代理类需要实现的接口的集合中// 如果目标类本身不是一个接口,但是是经过jdk代理后的一个类// 那么获取这个代理后的类所有实现的接口,并添加到需要实现的接口集合中if (specifiedInterfaces.length == 0) {Class<?> targetClass = advised.getTargetClass();if (targetClass != null) {if (targetClass.isInterface()) {advised.setInterfaces(targetClass);}else if (Proxy.isProxyClass(targetClass)) {advised.setInterfaces(targetClass.getInterfaces());}specifiedInterfaces = advised.getProxiedInterfaces();}}// 第三步:为代理类添加三个默认需要实现的接口,分别是// 1.SpringProxy,一个标记接口,代表这个类是通过Spring的AOP代理生成的// 2.Advised,提供了管理通知的方法// 3.DecoratingProxy,用户获取到真实的目标对象// 这个真实对象指的是在嵌套代理的情况下会获取到最终的目标对象// 而不是指返回这个ProxyFactory的targetboolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));int nonUserIfcCount = 0;if (addSpringProxy) {nonUserIfcCount++;}if (addAdvised) {nonUserIfcCount++;}if (addDecoratingProxy) {nonUserIfcCount++;}Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);int index = specifiedInterfaces.length;if (addSpringProxy) {proxiedInterfaces[index] = SpringProxy.class;index++;}if (addAdvised) {proxiedInterfaces[index] = Advised.class;index++;}if (addDecoratingProxy) {proxiedInterfaces[index] = DecoratingProxy.class;}return proxiedInterfaces;
}
1.3、处理器的invoke方法
- 目标对象是一个JDK
代理对象
,所以执行目标方法
会被上面实例化的JdkDynamicAopProxy代理对象的invoke()
方法拦截 - 如果当前方法匹配到增强器,则执行整个
拦截器链
(多个通知方法组成) - 如果当前方法没有匹配到增强器,则使用
反射
调用目标类方法
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 {// 首先处理的是hashCode跟equals方法// 如果接口中没有定义这两个方法,那么会调用本类中定义的equals方法// 前面我们也说过了,只有当两个类的目标对象,通知以及实现的接口都相等的情况下// equals才会返回true// 如果接口中定义了这两个方法,那么最终会调用目标对象中的方法if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {return equals(args[0]);}else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {return hashCode();}// 也就是说我们调用的是DecoratingProxy这个接口中的方法// 这个接口中只定义了一个getDecoratedClass方法,用于获取到// 最终的目标对象,在方法实现中会通过一个while循环来不断接近// 最终的目标对象,直到得到的目标对象不是一个被代理的对象才会返回else if (method.getDeclaringClass() == DecoratingProxy.class) {return AopProxyUtils.ultimateTargetClass(this.advised);}// 说明调用的是Advised接口中的方法,这里只是单纯的进行反射调用else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&method.getDeclaringClass().isAssignableFrom(Advised.class)) {return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);}Object retVal;// 说明需要将代理类暴露到线程上下文中// 调用AopContext.setCurrentProxy方法将其放入到一个threadLocal中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();}// 这里是处理一种特殊情况,就是当执行的方法返回值为this的情况// 这种情况下,需要返回当前的代理对象而不是目标对象Class<?> returnType = method.getReturnType();if (retVal != null && retVal == target &&returnType != Object.class && returnType.isInstance(proxy) &&!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {retVal = proxy;}else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);}return retVal;}finally {if (target != null && !targetSource.isStatic()) {targetSource.releaseTarget(target);}if (setProxyContext) {AopContext.setCurrentProxy(oldProxy);}}
}
获取拦截器链
- 先去缓存中获取,获取不到再进行复杂耗时的逻辑解析,然后放入缓存中,下次就直接获取到了
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method,@Nullable Class<?> targetClass) {// 目标对象方法的缓存键// public abstract int com.xc.service.Calculate.add(int,int)MethodCacheKey cacheKey = new MethodCacheKey(method);// 先去缓存中获取List<Object> cached = this.methodCache.get(cacheKey);if (cached == null) {// 缓存中没有,则进行逻辑解析cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);// 放入缓存中this.methodCache.put(cacheKey, cached);}return cached;
}
- 获取当前bean所有的增强器,匹配当前
method
的增强器 - 将匹配到的Advisor(增强器)转化为方法拦截器(实现MethodInterceptor接口)
- 环绕通知、后置通知、异常通知已经实现MethodInterceptor接口,这里直接返回
前置通知
和返回通知
实现MethodInterceptor接口重新包装了一下
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());// 是否有引入通知boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();// 获取到所有的通知for (Advisor advisor : config.getAdvisors()) {// 除了引入通知外,可以认为所有的通知都是一个PointcutAdvisorif (advisor instanceof PointcutAdvisor) {PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;// config.isPreFiltered:代表的是配置已经过滤好了,是可以直接应用的// 这句代码的含义就是配置是预过滤的或者在类级别上是匹配的if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {// 接下来要判断在方法级别上是否匹配MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {// 将通知转换成对应的拦截器// 有些通知本身就是拦截器,例如环绕通知// 有些通知需要通过一个AdvisorAdapter来适配成对应的拦截器// 例如前置通知,后置通知,异常通知等// 其中MethodBeforeAdvice会被适配成MethodBeforeAdviceInterceptor// AfterReturningAdvice会被适配成AfterReturningAdviceInterceptor// ThrowAdvice会被适配成ThrowsAdviceInterceptorMethodInterceptor[] interceptors = registry.getInterceptors(advisor);// 如果是动态的拦截,会创建一个InterceptorAndDynamicMethodMatcher// 动态的拦截意味着需要根据具体的参数来决定是否进行拦截if (mm.isRuntime()) {for (MethodInterceptor interceptor : interceptors) {interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));}}else {interceptorList.addAll(Arrays.asList(interceptors));}}}}else if (advisor instanceof IntroductionAdvisor) {// 说明是引入通知IntroductionAdvisor ia = (IntroductionAdvisor) advisor;if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {// 前文我们有提到过,引入通知实际就是通过一个拦截器// 将方法交由引入的类执行而不是目标类Interceptor[] interceptors = registry.getInterceptors(advisor);interceptorList.addAll(Arrays.asList(interceptors));}}else {// 可能会扩展出一些通知,一般不会Interceptor[] interceptors = registry.getInterceptors(advisor);interceptorList.addAll(Arrays.asList(interceptors));}}return interceptorList;
}
返回通知包装例子:
执行拦截器链
- ReflectiveMethodInvocation的proceed方法
- currentInterceptorIndex:当前拦截器链下标索引,从-1开始计算
- interceptorsAndDynamicMethodMatchers:拦截器链
public Object proceed() throws Throwable {// 两者相等,证明已经 proceed 已经执行拦截器的总数量// 满足这个条件,说明已经执行完了最后一个拦截器,那么直接反射调用目标方法if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();}// 获取到下一个要执行的拦截器Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);// 前面构建拦截器链的时候我们可以看到,动态的拦截的话会创建一个InterceptorAndDynamicMethodMatcher// 一般没有,不考虑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 {// 调用拦截器中的invoke方法,可以看到这里将this作为参数传入了// 所以我们在拦截器中调用 MethodInvocation的proceed时又会进行入当前这个方法// 然后去执行链条中的下一个拦截器 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}
}
拦截器链顺序
- 根据切面类获取通知方法的时候,就给通知排序了,一直应用到拦截器链
- Around:环绕通知
- Before:前置通知
- After:后置(最终)通知
- AfterReturning:返回通知
- AfterThrowing:异常通知
- 在获取当前bean的增强器时候会添加一个ExposeInvocationInterceptor拦截器,放在最前面,第一个执行
注意:这只是拦截器执行顺序
2、各种拦截器作用
2.1、ExposeInvocationInterceptor默认拦截器
- 将MethodInvocation也就是ReflectiveMethodInvocation,放到本地线程ThreadLocal中
- ReflectiveMethodInvocation包含
拦截器链
、目标类
、当前执行方法和参数
- 后续的通知器里就可以根据
ExposeInvocationInterceptor.currentInvocation()
来得到ReflectiveMethodInvocation
public final class ExposeInvocationInterceptor implements MethodInterceptor, PriorityOrdered, Serializable {...private static final ThreadLocal<MethodInvocation> invocation =new NamedThreadLocal<>("Current AOP method invocation");public static MethodInvocation currentInvocation() throws IllegalStateException {MethodInvocation mi = invocation.get();return mi;}@Override@Nullablepublic Object invoke(MethodInvocation mi) throws Throwable {MethodInvocation oldInvocation = invocation.get();invocation.set(mi);try {return mi.proceed();}finally {invocation.set(oldInvocation);}}...
}
2.2、AspectJAroundAdvice环绕通知拦截器
MethodInvocationProceedingJoinPoint类图
连接点对象
MethodInvocationProceedingJoinPoint- 内部维护MethodInvocation对象,即
ReflectiveMethodInvocation
对象
- 内部维护MethodInvocation对象,即
- 核心在于invokeAdviceMethod方法,此方法是父类AbstractAspectJAdvice中的方法,所有的通知对象都会继承此方法
@Override
public Object invoke(MethodInvocation mi) throws Throwable {if (!(mi instanceof ProxyMethodInvocation)) {throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);}// MethodInvocation对象,即ReflectiveMethodInvocationProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;// 创建连接点对象MethodInvocationProceedingJoinPoint,内部维护MethodInvocation对象ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);JoinPointMatch jpm = getJoinPointMatch(pmi);// 调用环绕通知方法return invokeAdviceMethod(pjp, jpm, null, null);
}
argBinding绑定参数
protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,@Nullable Object returnValue, @Nullable Throwable t) throws Throwable {// 当前拦截器 returnValue(返回值)、t(异常)为空// argBinding:绑定参数return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}protected Object[] argBinding(JoinPoint jp, @Nullable JoinPointMatch jpMatch,@Nullable Object returnValue, @Nullable Throwable ex) {// 解析参数,默认这里不需要再解析,前面创建Advisor的时候已经解析过一次了。calculateArgumentBindings();// 通知方法的参数Object[] adviceInvocationArgs = new Object[this.parameterTypes.length];int numBound = 0;// 由于此方法是执行切面通知的通用方法,这里joinPointArgumentIndex一般是0// 说明此方法参数为JoinPoint对象。具体类型是根据我们的通知方法的参数类型解析出来的。if (this.joinPointArgumentIndex != -1) {adviceInvocationArgs[this.joinPointArgumentIndex] = jp;numBound++;}else if (this.joinPointStaticPartArgumentIndex != -1) {// 如果参数类型是JoinPoint.StaticPart,则给定此对象。一般我们不会给定此类型。adviceInvocationArgs[this.joinPointStaticPartArgumentIndex] = jp.getStaticPart();numBound++;}// argumentBindings一般是后置通知或最终通知以及异常通知。我们方法上给定参数对象的变量名。// 满足上述条件才有会进入此if逻辑。if (!CollectionUtils.isEmpty(this.argumentBindings)) {// binding from pointcut match// JoinPointMatch对象是前面从ProxyMethodInvocation中获取,一般我们不会设置,默认返回null。if (jpMatch != null) {PointcutParameter[] parameterBindings = jpMatch.getParameterBindings();for (PointcutParameter parameter : parameterBindings) {String name = parameter.getName();Integer index = this.argumentBindings.get(name);adviceInvocationArgs[index] = parameter.getBinding();numBound++;}}// binding from returning clause// 如果是目标方法执行后的通知,则可以获取它的返回值。// 如果我们的通知方法参数给定了此返回值参数,这里就会进行返回值赋值。if (this.returningName != null) {Integer index = this.argumentBindings.get(this.returningName);adviceInvocationArgs[index] = returnValue;numBound++;}// binding from thrown exception// 这里就是异常通知时,如果方法参数上指定,则进行异常对象赋值。if (this.throwingName != null) {Integer index = this.argumentBindings.get(this.throwingName);adviceInvocationArgs[index] = ex;numBound++;}}if (numBound != this.parameterTypes.length) {throw new IllegalStateException("Required to bind " + this.parameterTypes.length +" arguments, but only bound " + numBound + " (JoinPointMatch " +(jpMatch == null ? "was NOT" : "WAS") + " bound in invocation)");}// 返回最终的参数对象数组。return adviceInvocationArgs;
}
- 当执行
环绕通知
时,我们的通知方法参数只有ProceedingJoinPoint
对象 - 当执行其他通知时,参数也有ProceedingJoinPoint对象,但是只能用
父类对象JoinPoint
接收- 如果使用ProceedingJoinPoint对象接收,则解析@Aspect切面的通知创建通知对象时候抛出异常
- 另外idea也会提示错误,只有环绕通知可以使用ProceedingJoinPoint
- 如果使用ProceedingJoinPoint对象接收,则解析@Aspect切面的通知创建通知对象时候抛出异常
- 当执行
前置通知
和后置(最终)通知
时,通知方法参数只有JoinPoint
对象 - 当执行
返回通知
时,参数有JoinPoint
对象- 还会根据注解指定的返回参数变量名,给定对应的目标方法返回值
- 还会根据注解指定的返回参数变量名,给定对应的目标方法返回值
- 当执行
异常通知
时,参数有JoinPoint
对象- 还会根据注解指定的异常变量名称,给定对应的异常对象
- 还会根据注解指定的异常变量名称,给定对应的异常对象
反射执行通知方法
- 回到AspectJAroundAdvice环绕通知的拦截器
- aspectJAdviceMethod:切面类中的通知方法(这里是@Around注解的方法)
- 直接通过BeanFactory根据name获取bean
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {Object[] actualArgs = args;if (this.aspectJAdviceMethod.getParameterCount() == 0) {actualArgs = null;}try {// 使给定的方法可访问ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);// 反射调用增强处理方法return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);}catch (IllegalArgumentException ex) {throw new AopInvocationException("Mismatch on arguments to advice method [" +this.aspectJAdviceMethod + "]; pointcut expression [" +this.pointcut.getPointcutExpression() + "]", ex);}catch (InvocationTargetException ex) {throw ex.getTargetException();}
}// 直接通过BeanFactory根据name获取bean
@Override
public Object getAspectInstance() {return this.beanFactory.getBean(this.name);
}
进入环绕通知方法
通知方法的执行顺序
- Around—Before—目标方法—After—AfterReturning Or AfterThrowing
- 回到上面环绕通知方法,那么
joinPoint.proceed()
就是去执行其他通知方法和目标方法 - 进入joinPoint.proceed()的方法,其实就回到了jdk代理的invoke方法中的处理拦截器链
- 此时已经是第三次进入这个方法,最终会调用最后的
invoke
方法进入前置通知方法
2.3、MethodBeforeAdviceInterceptor前置通知拦截器
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {// 前置通知对象private final MethodBeforeAdvice advice;public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {Assert.notNull(advice, "Advice must not be null");this.advice = advice;}@Override@Nullablepublic Object invoke(MethodInvocation mi) throws Throwable {// 先执行此前置通知的方法this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());// 调用下一个通知逻辑return mi.proceed();}
}
- 执行通用父类的通知执行逻辑,上面已经分析过了
- 组装JoinPoint对象参数,调用前置通知方法
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {// 执行通用父类的通知执行逻辑invokeAdviceMethod(getJoinPointMatch(), null, null);
}
- argNames就是设置注解方法的
参数名
,如果有多个,可以设置多个,用,隔开,一般不设置 - 执行完方法,回到上面的 mi.proceed(),再次回到ReflectiveMethodInvocation拦截器链,进入
后置(最终)通知
2.4、AspectJAfterAdvice后置(最终)通知拦截器
- mi.proceed():调用下一个通知逻辑,也就是返回通知
finally
里的invokeAdviceMethod:执行通用父类的通知执行逻辑,无论如何都会执行
public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice, Serializable {public AspectJAfterAdvice(Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {super(aspectJBeforeAdviceMethod, pointcut, aif);}@Override@Nullablepublic Object invoke(MethodInvocation mi) throws Throwable {try {return mi.proceed();}finally {invokeAdviceMethod(getJoinPointMatch(), null, null);}}@Overridepublic boolean isBeforeAdvice() {return false;}@Overridepublic boolean isAfterAdvice() {return true;}
}
- 返回通知或异常通知执行完,才会进入后置(最终)通知的方法
2.4、AspectJAfterAdvice返回通知拦截器
- mi.proceed():调用下一个通知逻辑,也就是异常通知
- advice.afterReturning:返回通知的逻辑
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {private final AfterReturningAdvice advice;public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {Assert.notNull(advice, "Advice must not be null");this.advice = advice;}@Override@Nullablepublic Object invoke(MethodInvocation mi) throws Throwable {Object retVal = mi.proceed();// 如果发生异常,则返回通知不执行,返回到异常通知逻辑,被捕获this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());return retVal;}
}
2.5、AspectJAfterThrowingAdvice异常通知拦截器
public class AspectJAfterThrowingAdvice extends AbstractAspectJAdviceimplements MethodInterceptor, AfterAdvice, Serializable {...@Override@Nullablepublic Object invoke(MethodInvocation mi) throws Throwable {try {return mi.proceed();}catch (Throwable ex) {if (shouldInvokeOnThrowing(ex)) {invokeAdviceMethod(getJoinPointMatch(), null, ex);}throw ex;}}private boolean shouldInvokeOnThrowing(Throwable ex) {return getDiscoveredThrowingType().isAssignableFrom(ex.getClass());}
}
- mi.proceed():回到拦截器链,会执行目标方法
- invokeAdviceMethod:执行通用父类的通知执行逻辑,组装参数,调用异常通知
3、总结通知执行顺序
没有异常情况
环绕通知(前) ➡️ 前置通知 ➡️ 目标方法 ➡️ 返回通知
➡️ 后置(最终通知) ➡️ 环绕通知(后)
有异常情况
环绕通知(前) ➡️ 前置通知 ➡️ 目标方法 ➡️ 异常通知
➡️ 后置(最终通知)
这篇关于Spring源码解析(九):AOP源码之@Aspect所有相关注解解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!