[Spring]AnnotationAwareAspectJAutoProxyCreator-@AspectJ的解析器

AnnotationAwareAspectJAutoProxyCreator职能

AnnotationAwareAspectJAutoProxyCreator是用来处理被@AspectJ注解标准的切面类和Spring Advisors的.
其中,Spring Advisors的处理规则遵循AbstractAdvisorAutoProxyCreator中建立的规则.

UML

UML

我们从类图可以看到,AnnotationAwareAspectJAutoProxyCreator的组成结构还是稍微复杂的。下面我们来过一下其中比较重要的接口.

  • AopInfrastructureBean: 实现该接口的类会被标记为Spring内部的基础类,Spring AOP并不会对这类型的Bean进行代理.
  • 与Aware相关的接口: 通过此类接口获取容器的BeanFactory和ClassLoader.
  • ProxyConfig: 用于创建代理的配置类,以确保所有代理创建者都具有一致的属性.内部可配置proxyTargetClassexposeProxyoptimize等属性
  • ProxyProcessorSupport: 具有代理处理器通用功能的基类,此外,还特地提供了ClassLoader的管理和evaluateProxyInterfaces方法,ProxyFactory可以通过evaluateProxyInterfaces方法获取给定bean类上的接口.
  • InstantiationAwareBeanPostProcessor: Spring AOP中会在实例化前判断是否需要创建用户自定义的代理类,进而影响Spring Bean的声明周期.
  • SmartInstantiationAwareBeanPostProcessor: 重量级方法->getEarlyBeanReference,当Spring Bean发生循环依赖的时候,决定是否要将创建代理的时机提前.
  • BeanPostProcessor: AbstractAutoProxyCreator会在postProcessAfterInitialization中来解析当前Bean是否需要代理,正常的Bean是在此处进行代理的,当执行到这步的时候,通常Spring Bean已经完成实例化、初始化了。
  • AbstractAutoProxyCreator: 继承了ProxyProcessorSupportSmartInstantiationAwareBeanPostProcessor,是Spring AOP的代理创建器,将匹配代理的地方交由子类去实现.同时,它还是getEarlyBeanReference方法的实现者.
  • AbstractAdvisorAutoProxyCreator: 提供为每个Bean选择特定的advisor进行代理的功能,提供findCandidateAdvisorsgetAdvicesAndAdvisorsForBean方法用于寻找候选的advisors和为bean匹配advisors.
  • AspectJAwareAdvisorAutoProxyCreator: 提供了对advisors进行排序的功能,同时为了兼容XML的切面配置解析,也保留了shouldSkip
  • AnnotationAwareAspectJAutoProxyCreator: Spring用于解析切面类,将需要执行的通知方法转化成Spring Advisor.

Spring Advisor

Spring中的Advisor接口是Spring AOP的基础接口,一个Advisor可以持有一个pointcut和一个AOP advice.Spring AOP正是通过将被AspectJ标注的类中的不同Advice解析成Advisor调用链来执行切面逻辑的。

Advised-操作Advisor

public interface Advised extends TargetClassAware {

	// 返回当前的advised配置是否被冻结
	boolean isFrozen();

    // 代理完整的目标类而不是指定的接口
	boolean isProxyTargetClass();

    // 返回由AOP代理代理的接口。
    // 将不包括目标类别,也可以将其作为代理。
	Class<?>[] getProxiedInterfaces();

    // 确定是否代理给定的接口
	boolean isInterfaceProxied(Class<?> intf);

    // 更改此建议对象使用的TargetSource。
    // 仅在未冻结配置的情况下有效。
	void setTargetSource(TargetSource targetSource);

    // 返回此Advised对象使用的TargetSource。
	TargetSource getTargetSource();

    // 设置代理是否应由AOP框架公开为ThreadLocal以便通过AopContext类进行检索。
    // 默认值为false,以实现最佳性能。
	void setExposeProxy(boolean exposeProxy);

    // 当前代理工厂是是否将代理类引用通过ThrealLocal管理起来.
	boolean isExposeProxy();

	// 获取当前代理的所有advisors
	Advisor[] getAdvisors();

	// 向当前proxy的advisor调用链追加一个advisor
	void addAdvisor(Advisor advisor) throws AopConfigException;

	// 向当前proxy的advisor调用链中的某个位置插入一个advisor
	void addAdvisor(int pos, Advisor advisor) throws AopConfigException;

	// 移除给定的advisor
	boolean removeAdvisor(Advisor advisor);

	// 移除某个位置中的advisor
	void removeAdvisor(int index) throws AopConfigException;

	// 获取当前advisor在执行链中的位置. -1代表没有任何的advisor
	int indexOf(Advisor advisor);

	// 替代某个advisor
	boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;

	// 向advice的拦截链中添加给定的AOP Alliance advice
	void addAdvice(Advice advice) throws AopConfigException;

	void addAdvice(int pos, Advice advice) throws AopConfigException;

	boolean removeAdvice(Advice advice);

	int indexOf(Advice advice);

	// 返回AOP代理的配置项。
	String toProxyConfigString();

}
复制代码

Spring 官网对advised接口的描述

TargetSource

Spring AOP并不是直接代理目标类,而是通过代理TargetSource接口进而实现动态代理.
简单来说即: Spring AOP->TargetSource->targetObject

  • UML

targetSource

Spring官网对TargerSource的介绍

加载切面类并解析advisor

  • AbstractAutoProxyCreator#postProcessBeforeInstantiation
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
		// 从缓存中获取当前BeanClass的Class对象,在advisedBeans这个Map中,以class为key
		// 同时,该class还充当proxyTypes这个Map中的key
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
			// 如果当前类已经被动态代理了,不进行任何操作
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			// 当前beanClass是否实现Advice、Pointcut、Advisor、AopInfrastructureBean
			// 是否需要跳过解析
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}

		// 如果当前beanClass存在用户自定义的TargetSource,则进行代理
		// 在Spring AOP中,动态代理并不是直接代理target对象的,而是通过代理TargetSource来间接代理target对象
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
		if (targetSource != null) {
			if (StringUtils.hasLength(beanName)) {
				this.targetSourcedBeans.add(beanName);
			}
			// 获取当前bean的advisors
			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
			// 创建代理类
			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		return null;
	}
复制代码
  1. 需要过滤已经创建过动态代理的类,advisedBeans这个Map便是缓存已经被Spring AOP处理过的BeanClass.
  2. 其中isInfrastructureClass会过滤掉Spring AOP框架内部的基类,同时会识别当前是否标注了@AspectJ与被ajc编译器所编译.
  3. 如果当前用户自定义实现了TargetSource接口,那么AbstractAutoProxyCreator会为用户自定义的TargetSource创建代理.

我们深入isInfrastructureClass这个方法看看,step into!

isInfrastructureClass-忽略Spring AOP的基础服务类

  • org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#isInfrastructureClass
@Override
	protected boolean isInfrastructureClass(Class<?> beanClass) {
	    
		return (super.isInfrastructureClass(beanClass) ||
				(this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass)));
	}
复制代码

父类中的AbstractAutoProxyCreator调用了AnnotationAwareAspectJAutoProxyCreator中的isInfrastructureClass,这里有2个判断:

  1. 调用父类的isInfrastructureClass,返回true则直接中断.

父类执行isInfrastructureClass的逻辑为:当前beanClass是否实现AdvicePointcutAdvisorAopInfrastructureBean.
2. 判断当前beanClass是否为切面类.isApsect的逻辑比较简单:beanClass上是否标注了@Aspect注解并且没有被ajc编译器编译过.

  • org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect
	public boolean isAspect(Class<?> clazz) {
	    // 类上是否标注@Aspect并且没有被ajc编译器编译过
		return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
	}
复制代码

shouldSkip-将切面类解析成advisor

  • org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#shouldSkip
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
	// TODO: Consider optimization by caching the list of the aspect names
	// 查找候选的advisors
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
	for (Advisor advisor : candidateAdvisors) {
		if (advisor instanceof AspectJPointcutAdvisor &&
				((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
			return true;
		}
	}
	return super.shouldSkip(beanClass, beanName);
}
复制代码

shouldSkip是Spring AOP构建advisor的入口,spring会在每次执行postProcessBeforeInstantiation的时候,解析每个advisor,解析完成后将advisors进行缓存,进而判断当前的beanClass和beanName是否已经解析完毕. 下面,我们来看看findCandidateAdvisors这个方法做了什么,step into.

  • org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
@Override
protected List<Advisor> findCandidateAdvisors() {
	// Add all the Spring advisors found according to superclass rules.
	// 添加根据超类规则找到的所有Spring advisors.从层级关系我们可以知道,
	// AspectJAwareAdvisorAutoProxyCreator提供对XML或者实现接口的AOP配置解析
	List<Advisor> advisors = super.findCandidateAdvisors();
	// Build Advisors for all AspectJ aspects in the bean factory.
	if (this.aspectJAdvisorsBuilder != null) {
		// 注解驱动的AOP切面解析类解析
		advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
	}
	return advisors;
}
复制代码

这里面findCandidateAdvisors分成了两条线路:

  1. 调用父类AspectJAwareAdvisorAutoProxyCreator#finCandidateAdvisors提供对XML或者实现接口的AOP配置解析成advisor列表.
  2. 解析注解形式的Aspect成advisor列表.

最后,都添加进advisor列表中.

解析advisor类型的bean.
  • org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
// BeanFactoryAdvisorRetrievalHelperAdapter#findAdvisorBeans
return this.advisorRetrievalHelper.findAdvisorBeans();
}
复制代码

这里进行了一个helper的委托,真正执行者为BeanFactoryAdvisorRetrievalHelperAdapter#findAdvisorBeans.

  • org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
/**
 * <p>Find all eligible Advisor beans in the current bean factory,
 * ignoring FactoryBeans and excluding beans that are currently in creation.</p>
 * 在当前beanFactory中查找所有有资格的advisor.<br>
 * 对FactoryBean和正在创建中的bean不生效 <br>
 * @return the list of {@link org.springframework.aop.Advisor} beans
 * @see #isEligibleBean
 */
public List<Advisor> findAdvisorBeans() {
	// Determine list of advisor bean names, if not cached already.
	// 从缓存中获取容器中所有的advisor bean的名字数组
	String[] advisorNames = this.cachedAdvisorBeanNames;
	if (advisorNames == null) {
		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the auto-proxy creator apply to them!
		// 如果缓存中没有,那么从容器中以及其父容器中分析得到所有的advisor bean的名称
		// BeanFactoryUtils.beanNamesForTypeIncludingAncestors此处是找到类型为advisor的bean
		// 注意,spring不推荐在此处实例化factoryBeans,因为spring需要保留所有未初始化的常规类
		// 以使自动代理创建者对其应用!
		advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
				this.beanFactory, Advisor.class, true, false);
		// 回种缓存
		this.cachedAdvisorBeanNames = advisorNames;
	}
	if (advisorNames.length == 0) {
		return new ArrayList<>();
	}

	List<Advisor> advisors = new ArrayList<>();
	for (String name : advisorNames) {
		// 是否为合适的bean,提供给用户自定义实现,默认返回true
		if (isEligibleBean(name)) {
			// 创建中的bean会被忽略,beanPostProcessor是每次加载bean都会触发的钩子
			// 所以在下次进来时,可能当前正在创建的bean已经被创建好了
			if (this.beanFactory.isCurrentlyInCreation(name)) {
				if (logger.isTraceEnabled()) {
					logger.trace("Skipping currently created advisor '" + name + "'");
				}
			}
			else {
				try {
					// 根据advisorName获取advisor实例
					advisors.add(this.beanFactory.getBean(name, Advisor.class));
				}
				catch (BeanCreationException ex) {
                    // 省略处理异常细节
				}
			}
		}
	}
	return advisors;
}
复制代码

首先,会尝试从缓存中获取advisorNames数组,里面存储了容器中所有的advisor bean的名字.如果无法从缓存中获取,那么重新加载符合条件的advisorNames数组,回种缓存.这里要注意: “`BeanFactoryUtils.beanNamesForTypeIncludingAncestors(

				this.beanFactory, Advisor.class, true, false);```中,传入的是```Advisor```类型.,也就是寻找类型为```Advisor```的beanName,并非所有beanName.  
复制代码

遍历advisorNames数组,对符合条件的advisor进行getBean操作,然后添加进advisors集合返回.

buildAspectJAdvisors-解析被@Aspect注解标记的类

/**
 * Look for AspectJ-annotated aspect beans in the current bean factory,
 * and return to a list of Spring AOP Advisors representing them.
 * <p>Creates a Spring Advisor for each AspectJ advice method.<br>
 * 1. 从容器获取所有的beanName集合 <br>
 * 2. 找到其中被@AspectJ标注的类 <br>
 * 3. 解析Aspect类,将其转化成advisors <br>
 * 4. 将result加入cache中 <br>
 * @return the list of {@link org.springframework.aop.Advisor} beans
 * @see #isEligibleBean
 */
public List<Advisor> buildAspectJAdvisors() {
	// 获取所有aspect类的beanName
	List<String> aspectNames = this.aspectBeanNames;
	// 如果aspectNames为空,那么进行加载
	if (aspectNames == null) {
		// 双重检查锁,防止多线程之间产生并发访问
		synchronized (this) {
			aspectNames = this.aspectBeanNames;
			if (aspectNames == null) {
				List<Advisor> advisors = new ArrayList<>();
				// 保存切面名称的集合
				aspectNames = new ArrayList<>();
				// 获取所有的beanName
				// BeanFactoryUtils.beanNamesForTypeIncludingAncestors传入的type为Object
				// 也就说查找所有的bean,spring在这里使用了缓存,避免每次加载消耗性能
				String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
						this.beanFactory, Object.class, true, false);
				// 遍历所有的beanName
				for (String beanName : beanNames) {
					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,因为在这种情况下,它们将由Spring容器缓存,但不会被编织。
					// 获取bean的类型
					Class<?> beanType = this.beanFactory.getType(beanName);
					if (beanType == null) {
						continue;
					}
					// org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.isAspect
					// 筛选出当前class是否标记了@Apsect注解
					if (this.advisorFactory.isAspect(beanType)) {
						// 将当前的beanName加入到aspectNames这个缓存中
						aspectNames.add(beanName);
						// 获取当前beanClass的aspect元数据
						// AjType中包含了切面的详细数据
						AspectMetadata amd = new AspectMetadata(beanType, beanName);
						// 获取切面的种类,通常为singleton
						if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
							MetadataAwareAspectInstanceFactory factory =
									new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
							// Aspect中的advice+pointcut可以组成一个个advisor
							// 举个例子,before、after、around每个都会搭配pointcut组成advisor
							List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
							if (this.beanFactory.isSingleton(beanName)) {
								// 如果bean是单例,存到单例缓存中
								this.advisorsCache.put(beanName, classAdvisors);
							}
							else {
								// 否则将工厂和beanName缓存
								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;
}
复制代码

方法比较长,但是总体的脉络我们还是可以总结一下:

  1. 尝试从缓存获取所有的aspectNames集合.如果缓存找不到,重新加载.执行的方法又是BeanFactoryUtils.beanNamesForTypeIncludingAncestors,只不过这次传入的类型是Object.class,也就是说,获取的是所有的beanNames.
  2. 遍历beanNames数组,通过name获取type,然后判断当前类是否为Aspect.也就是被@Aspect注解所标记.
  3. 如果是Aspect,构建AspectMetadata,AspectMetadata中保存了AjType,这是AspectJ框架的产物,通过它可以快速获取当前类的pointcutadvice等.Spring AOP正是借助AspectJ来获取切面类的信息的.此外,AspectJ还提供了很多切面模型种类,通常,我们的切面类都是为singleton-单例.
  4. 调用ReflectiveAspectJAdvisorFactory#getAdvisors来解析Aspect类,进而解析出List<Advisor>.
  • org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
	// 获取Aspect类的class
	Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
	// 获取Aspect的类名
	String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
	// 校验切面类,不可以为抽象类,需标记@Aspect
	// spring aop 不支持percflow、percflowbelow种类的aspect
	validate(aspectClass);

	// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
	// so that it will only instantiate once.
	// 使用装饰器模式包装MetadataAwareAspectInstanceFactory
	// 包装器类重写了getAspectInstance方法,并且保证当前的factory在使用时才进行加载(缓存)
	// 正如名字的意义一般 lazy singleton instance
	MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
			new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

	List<Advisor> advisors = new ArrayList<>();
	// 获取aspect切面类中的所有方法,会过滤掉被@Pointcut标记的方法
	// 获取到的List<Method>按照Around, Before, After, AfterReturning, AfterThrowing的顺序排序
	for (Method method : getAdvisorMethods(aspectClass)) {
		// 将方法解析成advisor
		Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), 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;
}
复制代码

getAdvisors就是我们关注的注解切面类解析逻辑了:

  1. 首先从aspectInstanceFactory中获取元数据进而获取切面类型和切面名称,随后对切面类进行校验-切面类不可以为抽象类,需标记@Aspect,同时,spring aop 不支持percflow、percflowbelow种类的aspect.
  2. 使用装饰器模式包装MetadataAwareAspectInstanceFactory来懒加载切面类实例.
  3. 获取当前类中标记@Pointcut注解外所有的Method集合,获取到的List按照Around, Before, After, AfterReturning, AfterThrowing的顺序排序.
  4. 遍历每一个Method,将符合条件的方法解析成advisor实例.
  5. 检查是否有属于introduction的成员,如果有便进行解析(@DeclareParents).
  6. 将解析完成的每一个advisor添加到返回的结果集中.
  • org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisor
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
		int declarationOrderInAspect, String aspectName) {
	// 验证aspectClass的合法性
	validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
	// 在切面的方法上构建pointcut表达式
	AspectJExpressionPointcut expressionPointcut = getPointcut(
			candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
	if (expressionPointcut == null) {
		return null;
	}
	// 实例化切面中的advice对象
	return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
			this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
复制代码
  1. 校验aspectClass的合法性,这个validate是复用的,跟上述的方法一致,逻辑就不重复讲了.
  2. 根据当前的adviceMethod与aspectClass构建出AspectJExpressionPointcut实例.它是一个pointcut表达式的实例.里面对AspectJ框架的表达式原语进行了部分的支持(11种).
  3. 通过getPointcut()获取到切点表达式之后,接下来就可以实例化adivce然后构建出advisor了,因为一个advisor = pointcut+advice.我们接着看InstantiationModelAwarePointcutAdvisorImpl这个方法是如何实例化advice的.
  • org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#InstantiationModelAwarePointcutAdvisorImpl
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
		Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
		MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
	// 当前的pointcut表达式
	this.declaredPointcut = declaredPointcut;
	// 切面Class
	this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
	// advice方法名称
	this.methodName = aspectJAdviceMethod.getName();
	// 方法参数类型
	this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
	// 方法实例
	this.aspectJAdviceMethod = aspectJAdviceMethod;
	// aspectJ的advisor工厂
	this.aspectJAdvisorFactory = aspectJAdvisorFactory;
	// aspectJ实例工厂
	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.
		// singleton模型的aspect
		this.pointcut = this.declaredPointcut;
		this.lazy = false;
		// 将切面中的advice进行实例化
		this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
	}
}
复制代码
  1. InstantiationModelAwarePointcutAdvisorImpl是advisor的子类.在这个构造函数内对传入的属性进行了设置,然后根据当前的切面模型决定是否需要延迟加载.
  2. 通常我们的切面类都是singleton的,所有会直接执行instantiateAdvice.
  • org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#instantiateAdvice
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);
}
复制代码

这里直接转发给了this.aspectJAdvisorFactory.getAdvice这个方法.继续跟踪.

  • org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
		MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
	// 获取切面类Class
	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来判断当前advice类型
	switch (aspectJAnnotation.getAnnotationType()) {
		// pointcut不解析
		case AtPointcut:
			if (logger.isDebugEnabled()) {
				logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
			}
			return null;
		// around类型的Advice
		case AtAround:
			springAdvice = new AspectJAroundAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		// before类型的Advice
		case AtBefore:
			springAdvice = new AspectJMethodBeforeAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		// after类型的Advice
		case AtAfter:
			springAdvice = new AspectJAfterAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		// afterReturning类型的Advice
		case AtAfterReturning:
			springAdvice = new AspectJAfterReturningAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterReturningAnnotation.returning())) {
				springAdvice.setReturningName(afterReturningAnnotation.returning());
			}
			break;
		// afterThrowing类型的Advice
		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...
	// 设置AspectName、DeclarationOrder,为后期执行调用链的时候做准备
	springAdvice.setAspectName(aspectName);
	springAdvice.setDeclarationOrder(declarationOrder);
	String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
	if (argNames != null) {
		springAdvice.setArgumentNamesFromStringArray(argNames);
	}
	springAdvice.calculateArgumentBindings();

	return springAdvice;
}
复制代码
  1. 解析Advice之前,Spring又又又对切面类进行了一次校验.
  2. 解析Advice,根据当前方法上的注解匹配对应的advice.例如:around、before、after、afterReturning、afterThrowing.
  3. 为advice实例配置切面名称、参数名称、声明顺序等.

OK,至此,Advice实例就被解析成功了.此时的InstantiationModelAwarePointcutAdvisorImpl成员属性中携带了pointcut+advice.

梳理加载Advisors的整体流程.

横切面解析.png

扩展阅读

【小家Spring】Spring AOP中@Pointcut切入点表达式最全面使用介绍
【小家Spring】Spring AOP核心类Pointcut解析,对PointcutExpression切点表达式解析原理分析(以AspectJExpressionPointcut为例)

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享