Spring源码解析(九):AOP源码之@Aspect所有相关注解解析

2024-02-26 05:10

本文主要是介绍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 AOPAspectJ
  • 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)
  • 将切面类所有的通知方法封装为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是否切面相关的类AdvicePointcutAdvisorAopInfrastructureBean
      • 平常使用的注解,也可以使用接口实现
    • 子类:当前 bean 是否切面(@Aspect注解的 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
  • 然后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);}
}
拦截器链顺序
  • 根据切面类获取通知方法的时候,就给通知排序了,一直应用到拦截器链
    1. Around:环绕通知
    2. Before:前置通知
    3. After:后置(最终)通知
    4. AfterReturning:返回通知
    5. 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对象
  • 核心在于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
      在这里插入图片描述
  • 当执行前置通知后置(最终)通知时,通知方法参数只有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);
}

进入环绕通知方法

在这里插入图片描述

通知方法的执行顺序
  • AroundBefore目标方法AfterAfterReturning 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所有相关注解解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/747790

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

sqlite3 相关知识

WAL 模式 VS 回滚模式 特性WAL 模式回滚模式(Rollback Journal)定义使用写前日志来记录变更。使用回滚日志来记录事务的所有修改。特点更高的并发性和性能;支持多读者和单写者。支持安全的事务回滚,但并发性较低。性能写入性能更好,尤其是读多写少的场景。写操作会造成较大的性能开销,尤其是在事务开始时。写入流程数据首先写入 WAL 文件,然后才从 WAL 刷新到主数据库。数据在开始