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简介

  • 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 {

	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
										BeanDefinitionRegistry registry) {
		// 注册AspectJ相关的处理组件AnnotationAwareAspectJAutoProxyCreator
		AopConfigUtils.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提供了定制的targetSource
    if (!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设置为false
        if (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,在 进入这个条件后,就会创建 ArrayList
    if (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,由子类定义规则,默认返回true
                    if (!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);
                        // 包装成 AspectMetadata
                        AspectMetadata 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<>();
    // 循环 切面的Name
    for (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的name
   String 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,  //0
        aspectName //切面名称
    );
}

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 @AfterThrowing
    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() + "]");
	}
 
    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();
            //设置后置返回值的参数name
            if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                springAdvice.setReturningName(afterReturningAnnotation.returning());
            }
            break;
            //如果是后置异常通知,则直接创建AspectJAfterThrowingAdvice实例
            //入参为:通知方法、切点表达式、切面实例
        case AtAfterThrowing:
            springAdvice = new AspectJAfterThrowingAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
            //设置后置异常通知 异常类型参数name
            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);
    // 通知注解中的参数名,换而言之就是获取 通知注解中的 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);
    // 判断是否是通过接口 默认是 False
    if (!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还是JDK
    return 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的target
    boolean 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()) {
        // 除了引入通知外,可以认为所有的通知都是一个PointcutAdvisor
        if (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会被适配成ThrowsAdviceInterceptor
                    MethodInterceptor[] 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
	@Nullable
	public 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对象,即ReflectiveMethodInvocation
	ProxyMethodInvocation 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
	@Nullable
	public 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
	@Nullable
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		finally {
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}
	
	@Override
	public boolean isBeforeAdvice() {
		return false;
	}
	@Override
	public 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
	@Nullable
	public 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 AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	...

	@Override
	@Nullable
	public 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、总结通知执行顺序

没有异常情况

环绕通知(前) ➡️ 前置通知 ➡️ 目标方法 ➡️ 返回通知 ➡️ 后置(最终通知) ➡️ 环绕通知(后)

有异常情况

环绕通知(前) ➡️ 前置通知 ➡️ 目标方法 ➡️ 异常通知 ➡️ 后置(最终通知)

评论 153
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冬天vs不冷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值