首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Spring源码之创建AOP代理之增强器的获取

Spring源码之创建AOP代理之增强器的获取

作者头像
@派大星
发布2023-06-28 14:30:28
发布2023-06-28 14:30:28
3601
举报
文章被收录于专栏:码上遇见你码上遇见你
前言

在上一篇博文中我们说到了通过自定义配置完成了对AnnotationAwareAspectJAutoProxyCreator类型的自动注册,那么这个类究竟做了什么工作从而完成 AOP 的操作呢?首先我们看一下AnnotationAwareAspectJAutoProxyCreator的类图结构,如图:

0cad5e140962669370459d2f0885150f

AOP 的源码解析操作入口

从 UML 类图中我们看到AnnotationAwareAspectJAutoProxyCreator这个类实现了BeanPostProcessor接口,而实现这个BeanPostProcessor后,当 Spring 加载这个 Bean 时会在实例化之前调用器postProcessorAfterIntialization方法,而我们就从这里进行分析 AOP 的逻辑

  • 首先我们先看一下它父类AbstractAutoProxyCreatorpostProcessorIntialization方法
  • 看源码(具体实现在AbstractAutoProxyCreator.class)
代码语言:javascript
复制
/**
 * Create a proxy with the configured interceptors if the bean is
 * identified as one to proxy by the subclass.
 * @see #getAdvicesAndAdvisorsForBean
 */
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
  if (bean != null) {
  // 根据bean的class 和 name构建出一个key  格式:beanClassName_beanName
  Object cacheKey = getCacheKey(bean.getClass(), beanName);
    if (this.earlyProxyReferences.remove(cacheKey) != bean) {
      // 如果它适合被代理,则需要指定封装bean
      return wrapIfNecessary(bean, beanName, cacheKey);
      }
  }
  return bean;
}

在上面代码中用到了方法wrapIfNecessary,进入到该函数方法的内部:

  • 看源码(具体实现在AbstractAutoProxyCreator.class)
代码语言:javascript
复制
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 如果已经处理过
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    // 无需增强
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    // 给定的bean类是否是一个基础设施类,基础设施类不应该被代理,或者配置了指定的bean不需要代理
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // 如果存在增强方法则创建
    // Create proxy if we have advice.
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        // 如果获取到了增强则需要针对增强进行代理
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 创建代理
        Object proxy = createProxy(
        bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

从上面的函数中我们可以大概看出代理的创建过程的一个雏形。当然真正的开始之前还需要一些个判断,比如是否已经处理过或者是 是否需要跳过的bean,而真正创建代理的代码是在getAdvicesAndAdvisorsForBean函数开始的。

创建代理需要两个步骤:

  1. 获取增强方法或增强器;
  2. 根据获取的增强来进行代理。

上述两个步骤其中逻辑是十分复杂的,首先来看看获取增强方法的逻辑实现。获取增强的方法getAdvicesAndAdvisorsForBean是在AbstractAdvisorAuroProxyCreator中实现的,代码如下:

  • 看源码(具体实现在AbstractAdvisorAuroProxyCreator.class)
代码语言:javascript
复制
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

  List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
  if (advisors.isEmpty()) {
    return DO_NOT_PROXY;
  }
  return advisors.toArray();
}
  • 源码分析 主要查看上述函数体内的findEligibleAdvisor方法。进入该方法实现也在AbstractAdvisorAuroProxyCreator.class
代码语言:javascript
复制
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    List<Advisor> candidateAdvisors = this.findCandidateAdvisors();
    List<Advisor> eligibleAdvisors = this.findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    this.extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = this.sortAdvisors(eligibleAdvisors);
    }

    return eligibleAdvisors;
  }
  • 源码分析 通过findEligbleAdvisor的具体实现我们看到,对于指定bean的增强方法的获取包含了两个步骤:
  1. 获取所有增强,
  2. 寻找所有增强中 对于bean的增强并应用(也就是寻找匹配bean的增强器)。

函数中的findCandidateAdvisorsfindAdvisorsThatCanApply便是做了这两件事 当然如果这个方法没有找到增强器,getAdvicesAndAdvisorsForBean就会返回一个DO_NOT_PROXY,DO_NOT_PROXY时已经定义好的null

获取增强器

从一开始我们分析的就是基于注解进行的AOP,所以对于findidateAdvisors的实现是由AnnotationAwareAspectJAutoProxyCreator类的findCandidateAdvisors方法完成的。

  • 看源码(具体实现在AnnotationAwareAspectJAutoProxyCreator.class)
代码语言:javascript
复制
@Override
protected List<Advisor> findCandidateAdvisors() {
    // Add all the Spring advisors found according to superclass rules.
	// 当使用注解方式配置AOP的时候并不是对xml配置文件的支持进行了丢弃
	// 在这里调用父类加载配置文件中的AOP声明
	List<Advisor> advisors = super.findCandidateAdvisors();
	// Build Advisors for all AspectJ aspects in the bean factory.
	if (this.aspectJAdvisorsBuilder != null) {
		advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
	}
	return advisors;
}
  • 源码解析:首先我们先看一下AnnotationAwareAspectJAutoProxyCreator.class这个类的UML,

在上图中我们看到AnnotationAwareAspectJAutoProxyCreator继承了AbstractAdvisorsAutoProxyCreator,在实现获取增强方法中保留了父类的获取配置文件中定义的增强,是由List<Advisor> advisors = super.findCandidateAdvisors();实现;

此外同时还添加了获取Bean的注解增强的功能,是由this.aspectJAdvisorsBuilder.buildAspectJAdvisors()这个方法实现的

Spring获取增强器(增强方法)的解析思路大致如下:

  1. 获取所有的beanName,这一步骤中所有的beanFactory中注册的Bean都会被提取出来。
  2. 遍历所有的beanName,并找出使用**@Aspect**注解声明的类,并进行进一步处理。
  3. 对于标记Aspect注解的类进行增强器的提取。
  4. 将提取结果加入缓存 接下来我们分析一下以上步骤的实现,首先
  • this.aspectJAdvisorsBuilder.buildAspectJAdvisors()源码的实现(具体实现在BeanFactoryAspectJAdvisorsBuilder.class)
代码语言:javascript
复制
public List<Advisor> buildAspectJAdvisors() {
    List<String> aspectNames = this.aspectBeanNames;

	if (aspectNames == null) {
		synchronized (this) {
			aspectNames = this.aspectBeanNames;
			if (aspectNames == null) {
				List<Advisor> advisors = new ArrayList<>();
				aspectNames = new ArrayList<>();
					// 获取所有的beanName
				String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
						this.beanFactory, Object.class, true, false);
				// 循环所有的beanName获取 获取声明AspectJ的类,找出对应的增强方法
				for (String beanName : beanNames) {
					// 不合法的bean 则略过,由子类定义规则返回true
					if (!isEligibleBean(beanName)) {
						continue;
					}
					// We must be careful not to instantiate beans eagerly as in this case they
					// would be cached by the Spring container but would not have been weaved.
					// 获取对应的bean Class类型
					Class<?> beanType = this.beanFactory.getType(beanName, false);
					if (beanType == null) {
						continue;
					}
					if (this.advisorFactory.isAspect(beanType)) {
						aspectNames.add(beanName);
						AspectMetadata amd = new AspectMetadata(beanType, beanName);
						if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
							MetadataAwareAspectInstanceFactory factory =
									new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
							// 解析标记AspectJ注解的增强方法
							List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
							if (this.beanFactory.isSingleton(beanName)) {
								// 将增强器加入缓存 下次可以直接取
								this.advisorsCache.put(beanName, classAdvisors);
							}
							else {
								this.aspectFactoryCache.put(beanName, factory);
							}
							advisors.addAll(classAdvisors);
						}
						else {
							// Per target or per this.
							if (this.beanFactory.isSingleton(beanName)) {
								throw new IllegalArgumentException("Bean with name '" + beanName +
										"' is a singleton, but aspect instantiation model is not singleton");
						    }
							MetadataAwareAspectInstanceFactory factory =
									new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
							this.aspectFactoryCache.put(beanName, factory);
							advisors.addAll(this.advisorFactory.getAdvisors(factory));
						}
					}
				}
				this.aspectBeanNames = aspectNames;
				return advisors;
			}
		}
	}

	if (aspectNames.isEmpty()) {
		return Collections.emptyList();
	}
	// 记录在缓存中
	List<Advisor> advisors = new ArrayList<>();
	for (String aspectName : aspectNames) {
		List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
		if (cachedAdvisors != null) {
			advisors.addAll(cachedAdvisors);
		}
		else {
			MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
			advisors.addAll(this.advisorFactory.getAdvisors(factory));
		}
	}
	return advisors;
}

执行到此,Spring就完成了Advisor的提取,在上面的步骤中最繁杂最重要的就是增强器的获取,而这一步又交给了getAdvisors方法去实现的。(this.advisorFactory.getAdvisors(factory);)

  • 首先看this.advisorFactory.isAspect(beanType)源码(具体实现在AbstractAspectJAdvisorFactory.class)
代码语言:javascript
复制
@Override
public boolean isAspect(Class<?> clazz) {
  return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}

private boolean hasAspectAnnotation(Class<?> clazz) {
  return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}

紧接着再查看一下findAnnotation方法:

代码语言:javascript
复制
@Nullable
public static <A extends Annotation> A findAnnotation(Class<?> clazz, @Nullable Class<A> annotationType) {
	if (annotationType == null) {
		return null;
	}

	// Shortcut: directly present on the element, with no merging needed?
	if (AnnotationFilter.PLAIN.matches(annotationType) ||
			AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
		// 判断此Class 是否存在Aspect.class注解
		A annotation = clazz.getDeclaredAnnotation(annotationType);
		if (annotation != null) {
			return annotation;
		}
		// For backwards compatibility, perform a superclass search with plain annotations
		// even if not marked as @Inherited: e.g. a findAnnotation search for @Deprecated
		Class<?> superclass = clazz.getSuperclass();
		if (superclass == null || superclass == Object.class) {
			return null;
		}
		return findAnnotation(superclass, annotationType);
	}

	// Exhaustive retrieval of merged annotations...
	return MergedAnnotations.from(clazz, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none())
			.get(annotationType).withNonMergedAttributes()
			.synthesize(MergedAnnotation::isPresent).orElse(null);
}

这里如果bean存在Aspect.class注解,那么就可以获取此bean的增强器了,接下来我们回到BeanFactoryAspectJAdvisorsBuilder类中查看this.advisorFactory.getAdvisors(factory);方法。

  • 看源码(具体实现在ReflectiveAspectJAdvisorFactory.class)
代码语言:javascript
复制
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
	// 获取标记AspectJ的类
	Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
	// 获取标记AspectJ的name
	String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
	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<>();
	// 对于aspect class的每一个带有注解的方法进行循环(除了@Pointcut注解的方法除外),取得Advisor,并添加到集合里
	// 这里应该取到的是Advice,然后取得我们自定义的切面类中的PointCut,组合成Advisor
	for (Method method : getAdvisorMethods(aspectClass)) {
		// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
		// to getAdvisor(...) to represent the "current position" in the declared methods list.
		// However, since Java 7 the "current position" is not valid since the JDK no longer
		// returns declared methods in the order in which they are declared in the source code.
		// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
		// discovered via reflection in order to support reliable advice ordering across JVM launches.
		// Specifically, a value of 0 aligns with the default value used in
		// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
		// 将类中的方法封装成Advisor
		Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
		if (advisor != null) {
			advisors.add(advisor);
		}
	}

	// If it's a per target aspect, emit the dummy instantiating aspect.
	if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
		Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
		advisors.add(0, instantiationAdvisor);
	}

	// Find introduction fields.
	for (Field field : aspectClass.getDeclaredFields()) {
		Advisor advisor = getDeclareParentsAdvisor(field);
		if (advisor != null) {
			advisors.add(advisor);
		}
	}

	return advisors;
}
普通增强器的获取

普通增强其的获取逻辑通过getAdvisor方法实现,实现步骤包括对切点的注解的获取以及根据注解信息生成增强。

首先我们看一下 **getAdvisorMethods(aspectClass)**这个方法,它很巧妙的使用接口定义一个匿名回调,把带有注解的Method都取出来,放到集合里。

  • 看源码
代码语言:javascript
复制
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;
}

然后在看一下函数体内的doWithMethods方法 具体实现在ReflectionUtils

代码语言:javascript
复制
public static void doWithMethods(Class<?> clazz, MethodCallback mc, @Nullable MethodFilter mf) {
  // Keep backing up the inheritance hierarchy.
    Method[] methods = getDeclaredMethods(clazz, false);
    for (Method method : methods) {
	if (mf != null && !mf.matches(method)) {
		continue;
	}
	try {
            mc.doWith(method);
	}
	catch (IllegalAccessException ex) {
		throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
	    }
    }
    if (clazz.getSuperclass() != null && (mf != USER_DECLARED_METHODS || clazz.getSuperclass() != Object.class)) {
	doWithMethods(clazz.getSuperclass(), mc, mf);
    }
    else if (clazz.isInterface()) {
      for (Class<?> superIfc : clazz.getInterfaces()) {
        doWithMethods(superIfc, mc, mf);
      }
    }
}

然后我们在回到ReflectiveAspectJAdvisorFactory.class类中获取普通增强器的getAdvisor方法

  • 看源码(具体实现在ReflectiveAspectJAdvisorFactory.class)
代码语言:javascript
复制
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
                              int declarationOrderInAspect, String aspectName) {
	validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
	// 获取Pointcut信息 主要是获取Pointcut表达式
	// 把Method对象也传进去的目的是,比较Method对象上的注解,是不是下面的注解的其中的一个,
	// 如果不是返回null;如果是就把Pointcut内容包装返回
	AspectJExpressionPointcut expressionPointcut = getPointcut(
	                candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
	if (expressionPointcut == null) {
		return null;
	}
	// 根据Pointcut信息生成增强器
	return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
	                this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
切点信息的获取

所谓获取切点信息就是指注解的表达式信息的获取,如@Before("test()")。

  • 看源码(具体在ReflectiveAspectJAdvisorFactory.class)
代码语言:javascript
复制
@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
  // 获取方法上的注解,比较Method对象上的注解是不是下面其中的一个,如果不是返回null
  // 被比较的注解:Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
  AspectJAnnotation<?> aspectJAnnotation =
          AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
  if (aspectJAnnotation == null) {
    return null;
  }
  // 使用AspectJExpressionPointcut实例封装获取的信息
  AspectJExpressionPointcut ajexp =
          new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
  // 提取到注解中的表达式并设置进去
  ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
  if (this.beanFactory != null) {
    ajexp.setBeanFactory(this.beanFactory);
  }
  return ajexp;
}

我们再看一下上面使用到的findAspectJAnnotationOnMethod方法的实现

  • 看源码(具体是现在AbstractAspectJAdvisorFactory.class)
代码语言:javascript
复制
@Nullable
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
    for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
        AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
        if (foundAnnotation != null) {
            return foundAnnotation;
        }
    }
    return null;
}

小插曲:注意一下上面的ASPECTJ_ANNOTATION_CLASSES变量,它设置了查找的注解类:

  • 源码
代码语言:javascript
复制
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = 
      new Class<?>[] { Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};

再次回到findAspectJAnnotationOnMethod方法的实现,里面使用了findAnnotation方法,跟踪该方法

  • 看源码(具体实现在AbstractAspectAdvisorFacrory.class)
代码语言:javascript
复制
/**
 * 获取指定方法上的注解 并使用AspectAnnotation进行封装
 * @param method
 * @param toLookFor
 * @param <A>
 * @return
 */
@Nullable
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
    A result = AnnotationUtils.findAnnotation(method, toLookFor);
    if (result != null) {
        return new AspectJAnnotation<>(result);
    } else {
        return null;
    }
}

此方法的功能是获取指定方法上的注解并使用AspectJAnnotation封装。

根据切点信息获取增强类

所有的增强都由Advisor实现类InstantiationModelAwarePointCutAdvisorImpl进行统一封装。我们简单看一下其构造函数:

代码语言:javascript
复制
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
            Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
            MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
    this.declaredPointcut = declaredPointcut;
    this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
    this.methodName = aspectJAdviceMethod.getName();
    this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
    this.aspectJAdviceMethod = aspectJAdviceMethod;
    this.aspectJAdvisorFactory = aspectJAdvisorFactory;
    this.aspectInstanceFactory = aspectInstanceFactory;
    this.declarationOrder = declarationOrder;
    this.aspectName = aspectName;
    if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        // Static part of the pointcut is a lazy type.
        Pointcut preInstantiationPointcut = Pointcuts.union(
                            aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
        // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
        // If it's not a dynamic pointcut, it may be optimized out
        // by the Spring AOP infrastructure after the first evaluation.
        this.pointcut = new PerTargetInstantiationModelPointcut(
                            this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
        this.lazy = true;
    } else {
        // A singleton aspect.
        this.pointcut = this.declaredPointcut;
        this.lazy = false;
        // 初始化Advice
        this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
    }
}

通过对上面的构造函数的分析,发现封装过程只是简单的将信息封装在类的实例中,所有的信息都是单纯的复制。在实例初始化的工程中还完成了对于增强器的初始化。因为不同的增强所体现的逻辑是不同的,比如@Before("test()")@After("test()")标签的不同就是增强器的位置不同,所以需要不同的增强器来完成不同的逻辑,而根据注解中的信息初始化对应的增强器就是在instantiateAdvice函数中实现的,继续跟踪源码:

代码语言:javascript
复制
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
    Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
                    this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
    return (advice != null ? advice : EMPTY_ADVICE);
}

接下来再继续跟踪getAdvice函数的具体实现

  • 看源码(具体实现在ReflectiveAspectJAdvisorFactory.class)
代码语言:javascript
复制
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

	Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
	validate(candidateAspectClass);

	AspectJAnnotation<?> aspectJAnnotation =
	    AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
	if (aspectJAnnotation == null) {
			return null;
	}

	// If we get here, we know we have an AspectJ method.
	// Check that it's an AspectJ-annotated class
	if (!isAspect(candidateAspectClass)) {
		throw new AopConfigException("Advice must be declared inside an aspect type: " +
				"Offending method '" + candidateAdviceMethod + "' in class [" +
				candidateAspectClass.getName() + "]");
	}

	if (logger.isDebugEnabled()) {
		logger.debug("Found AspectJ method: " + candidateAdviceMethod);
	}

	AbstractAspectJAdvice springAdvice;

	// 根据不同的注解类型封装不同的增强器
	switch (aspectJAnnotation.getAnnotationType()) {
		case AtPointcut:
			if (logger.isDebugEnabled()) {
				logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
			}
			return null;
		case AtAround:
			springAdvice = new AspectJAroundAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		case AtBefore:
			springAdvice = new AspectJMethodBeforeAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		case AtAfter:
			springAdvice = new AspectJAfterAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		case AtAfterReturning:
			springAdvice = new AspectJAfterReturningAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterReturningAnnotation.returning())) {
				springAdvice.setReturningName(afterReturningAnnotation.returning());
			}
			break;
		case AtAfterThrowing:
			springAdvice = new AspectJAfterThrowingAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
				springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
			}
			break;
		default:
			throw new UnsupportedOperationException(
					"Unsupported advice type on method: " + candidateAdviceMethod);
		}

	// Now to configure the advice...
	springAdvice.setAspectName(aspectName);
	springAdvice.setDeclarationOrder(declarationOrder);
	String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
	if (argNames != null) {
		springAdvice.setArgumentNamesFromStringArray(argNames);
	}
	springAdvice.calculateArgumentBindings();

	return springAdvice;
}
前置增强

从上面的函数中我们看到,Spring会根据不同的注解生成不同的增强器,具体表现在了switch (aspectJAnnotation.getAnnotationType()),根据不同的类型来生成。例如在AtBefore会对应AspectJMethodBeforeAdvice,早AspectJMethodBeforeAdvice中完成了增强逻辑,

并且这里的AspectJMethodBeforeAdvice最后被适配器封装成MethodBeforeAdviceInterceptor,

如何被封装的 这有机再在分析 我们先看一下MethodBeforeAdviceInterceptor的代码

  • 看源码
代码语言:javascript
复制
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
    private final MethodBeforeAdvice advice;
    /**
     * Create a new MethodBeforeAdviceInterceptor for the given advice.
     * @param advice the MethodBeforeAdvice to wrap
     */
    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();
    }
}

其中上述代码的MethodBeforeAdvice代表的前置增强的AspectJMethodBeforeAdvice,根据before方法来到这个类。

  • 看源码(具体实现在AspectJMethodBeforeAdvice.java)
代码语言:javascript
复制
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
    // 直接调用增强方法
    invokeAdviceMethod(getJoinPointMatch(), null, null);
}

继续跟踪函数体内的invokeAdviceMethod方法

  • 看源码(具体实现在AbstractAspectJAdvice.java)
代码语言:javascript
复制
protected Object invokeAdviceMethod(
            @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex)
            throws Throwable {
    return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}

接着继续根据函数体内的invokeAdviceMethodWithGivenArgs方法,

  • 看源码(具体实现在AbstractAspectJAdvice.java)
代码语言:javascript
复制
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
    Object[] actualArgs = args;
    if (this.aspectJAdviceMethod.getParameterCount() == 0) {
        actualArgs = null;
    }
    try {
        ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
        // 通过反射调用AspectJ注解类中的增强方法
        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();
    }
}

invokeAdviceMethodWithGivenArgs方法中的aspectJAdviceMethod正是对前置增强的方法,在这里实现了调用。

简单总结

前置通知的大致过程是在拦截器链中放置MethodBeforeAdviceInterceptor,而在MethodBeforeAdvivceInterceptor中又放置了AspectJMethodBeforeAdvice,并在调用invoke时首先串联调用。

后置增强

相比前置增强略有不同,后置增强没有提供中间的类,而是直接在拦截器中使用过了中间的AspectJAfterAdvice,也就是直接实现了MethodInterceptor

  • 看源码(AspectJAfterAdvice.java)
代码语言:javascript
复制
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;
    }
}

其他的几个增强器,下次具体来看

寻找匹配的增强器

前面的函数中已经完成了所有增强器的解析,也就是讲解完了关于findCandidateAdvisors方法;但是对于所有增强器来讲,并不一定都适用于当前的bean,还要取出适合的增强器,也就是满足我们配置的通配符的增强器,具体实现在findAdvisorsThatCanAply中,我们需要回到最初的AbstractAdvisorAuroProxyCreator类中,然后进入到findEligibleAdvisors函数内的findAdvisorsThatCanAply方法的实现:

  • 看源码(AbstractAdvisorAuroProxyCreator.java)
代码语言:javascript
复制
protected List<Advisor> findAdvisorsThatCanApply(
            List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    try {
        // 过滤已经得到的advisors
        return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    }
    finally {
        ProxyCreationContext.setCurrentProxiedBeanName(null);
    }
}

继续跟踪findAdvisorsThatCanApply方法:

  • 看源码(AOPUtils.java)
代码语言:javascript
复制
public static Boolean canApply(Pointcut pc, Class<?> targetClass, Boolean hasIntroductions) {
    Assert.notNull(pc, "Pointcut must not be null");
    // 通过Pointcut的条件判断此类是否匹配
    if (!pc.getClassFilter().matches(targetClass)) {
        return false;
    }
    MethodMatcher methodMatcher = pc.getMethodMatcher();
    if (methodMatcher == MethodMatcher.TRUE) {
        // No need to iterate the methods if we're matching any method anyway...
        return true;
    }
    IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
    if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
        introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
    }
    Set<Class<?>> classes = new LinkedHashSet<>();
    if (!Proxy.isProxyClass(targetClass)) {
        classes.add(ClassUtils.getUserClass(targetClass));
    }
    classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
    for (Class<?> clazz : classes) {
        // 反射获取类中所有的方法
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
        for (Method method : methods) {
            // 根据匹配原则判断该方法是否能匹配Pointcut中的规则,如果有一个方法匹配则返回true
            if (introductionAwareMethodMatcher != null ?
                                    introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
                                    methodMatcher.matches(method, targetClass)) {
                return true;
            }
        }
    }
    return false;
}
  • 源码分析

首先会判断bean是否满足切点的规则,如果能满足,则获取bean的所有方法,判断是否有方法能够匹配规则,有方法匹配规则就代表Advisor能作用于该bean,该方法就会返回true,然后findAdvisorsThatCanApply函数就会将Advisor加入到eligibleAdvisors中。

最后我们以注解的规则来看一下bean的method是怎样匹配Pointcut中的规则的
  • 看源码(AnnotationMethodMatcher.java)
代码语言:javascript
复制
@Override
public Boolean matches(Method method, Class<?> targetClass) {
    if (matchesMethod(method)) {
        return true;
    }
    // Proxy classes never have annotations on their redeclared methods.
    if (Proxy.isProxyClass(targetClass)) {
        return false;
    }
    // The method may be on an interface, so let's check on the target class as well.
    Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
    return (specificMethod != method && matchesMethod(specificMethod));
}
private Boolean matchesMethod(Method method) {
    // 可以看出判断该Advisor是否使用于bean中的method,只需看method上是否有Advisor的注解
    return (this.checkInherited ? AnnotatedElementUtils.hasAnnotation(method, this.annotationType) :
                    method.isAnnotationPresent(this.annotationType));
}

至此:在后置处理器中找到了所有匹配Bean中的增强器,

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-10-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码上遇见你 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • AOP 的源码解析操作入口
  • 获取增强器
    • 普通增强器的获取
      • 切点信息的获取
      • 根据切点信息获取增强类
      • 前置增强
      • 后置增强
    • 寻找匹配的增强器
    • 最后我们以注解的规则来看一下bean的method是怎样匹配Pointcut中的规则的
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档