Spring源码-AOP(七)-增强器的获取

前面一章简单说明了AOP代理的创建,接下来开始详细的分析其内部实现,分析增强器的获取

增强器的获取

在上一篇wrapIfNecessary()方法中,有相关的代码,我们具体分析下

【AbstractAutoProxyCreator】

	protected Object wrapIfNecessary(Object bean, @Nullable String beanName, Object cacheKey) {
..............
		// Create proxy if we have advice.
		//如果存在增强方法则创建代理
		Object[] specificInterceptors = 
		getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
.......................
	}

【AbstractAdvisorAutoProxyCreator】

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();
}
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;
}

此处代码做了两件事

  • 获取所以的增强
  • 寻找所有增强中适用于bean的增强并并应用,找不到的返回 DO_NOT_PROXY = null

由于我们分析的AOP是有注解实现的,所以对于findCandidateAdvisors()的实现需要查找从AnnotationAwareAspectJAutoProxyCreator中实现,如下:

【AnnotationAwareAspectJAutoProxyCreator】

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中的 findAdvisorBeans()间接继承了AbstractAutoProxyCreator中的findAdvisorBeans,在实现获取增强的方法中除了保留父类的获取配置文件中定义的增强外,同时添加获取bean的注解增强的功能,而真正实现是由 this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 实现的。

该处的实现思路如下:

  • 1、获取所有beanName,此处所有在beanFactory中注册的Bean都会被提出来
  • 2、变了所有beanName,并找出声明AspectJ注解的类,进一步处理
  • 3、对标记为AspectJ注解的类进行增强器的提取
  • 4、将提取结果加入缓存
    现在我们看下具体的实现
    【BeanFactoryAspectJAdvisorsBuilder】
    /**
     * 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.
     * @return the list of {@link org.springframework.aop.Advisor} beans
     * @see #isEligibleBean
     * 1、普通增强器的获取
     * 2、增加同步实例化增强器
     * 3、寻找匹配的增强器
     *
     */
    public List<Advisor> buildAspectJAdvisors() {
    	List<String> aspectNames = this.aspectBeanNames;
    
    	if (aspectNames == null) {
    		synchronized (this) {
    			aspectNames = this.aspectBeanNames;
    			if (aspectNames == null) {
    				List<Advisor> advisors = new LinkedList<>();
    				aspectNames = new LinkedList<>();
    				//获取所有bean的name
    				String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
    						this.beanFactory, Object.class, true, false);
    				//循环所有beanName找出对应的增强方法
    				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<?> beanType = this.beanFactory.getType(beanName);
    					if (beanType == null) {
    						continue;
    					}
    					//如果该类型存在aspect注解,做以下操作
    					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 LinkedList<>();
    	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;
    }
    

至此,我们已经完成了通知器的解析。往下我们就介绍最重要的也是最繁琐的通知器的获取。

2、获取通知器

由上段代码最后 this.advisorFactory.getAdvisors(factory) 可以看到这段就是获取通知器的代码,而看源码,是由AspectJAdviosrFactory 接口的getAdvisors()方法实现,下图是AspectJAdviosrFactory 的继承关系图

Spring源码-AOP(七)-增强器的获取

我们在其实现类ReflectiveAspectJAdvisorFactory 类中找到了他的 getAdvisors 实现

【ReflectiveAspectJAdvisorFactory】

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
	//获取标记为AspectJ的类
	Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
	//获取标记为Aspect 的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 LinkedList<>();
	//声明为pointcut的方法不处理
	for (Method method : getAdvisorMethods(aspectClass)) {
		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.
	//获取getDeclaredFields注解
	for (Field field : aspectClass.getDeclaredFields()) {
		Advisor advisor = getDeclareParentsAdvisor(field);
		if (advisor != null) {
			advisors.add(advisor);
		}
	}

	return advisors;
}

函数中完成了对增强器的获取,包括获取注解以及根据注解生成增强的步骤,然后考虑在配置中可能会将增强配置成延迟初始化,那么需要在首位加入同步实例化增强,保证增强使用之前的实例化,然后获取DeclareParents 注解。

接下来进行详细的分析

2.1、获取普通增强

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

看上段代码中
Advisor advisor = getAdvisor( );

【ReflectiveAspectJAdvisorFactory】

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;
	}
	//根据切点信息生成增强器
	return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
			this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

1、切点信息的获取,即指定注解表达式信息的获取,如@Before(“test()”)。

看上段代码中 getPointcut() 方法

【ReflectiveAspectJAdvisorFactory】

private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
	//获取方法上的注解
	AspectJAnnotation<?> aspectJAnnotation =
			AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
	if (aspectJAnnotation == null) {
		return null;
	}
	//使用AspectJExcepressionPointcut 实例封装获取的信息
	AspectJExpressionPointcut ajexp =
			new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
	//提取得到的注解的表达式,如
	//@Pointcut("execution(* test.TestBean.*(..))")
	ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
	if (this.beanFactory != null) {
		ajexp.setBeanFactory(this.beanFactory);
	}
	return ajexp;
}

接上段代码中获取方法上的注解,进入代码分析

@SuppressWarnings("unchecked")
@Nullable
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
	//这里可以看到很多敏感类,切面相关的注解类
	Class<?>[] classesToLookFor = new Class<?>[] {
			Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
	for (Class<?> c : classesToLookFor) {
		//获取指定方法上的注解,并使用AspectJAnnotation 封装
		AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) c);
		if (foundAnnotation != null) {
			return foundAnnotation;
		}
	}
	return null;
}

2、根据切点信息生成增强

所以的增强都由Advisor的实现类InstantiationModelAwarePointcutAdvisorImpl 统一封装。

我们回到 2.1、获取普通增强 中的代码看最后

【InstantiationModelAwarePointcutAdvisorImpl 】

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;
		this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
	}
}

封装过程只是简单地将信息封装在类的实例中而已,所以的信息单纯的赋值,在实例初始化的过程中还完成了对增强器的初始化。因为不同的增强所体现的逻辑是不同的,而根据注解中的信息初始化对应的增强器是在instantiateAdvice()完成的。

【InstantiationModelAwarePointcutAdvisorImpl 】

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);
}

与AspectJAdviosrFactory 接口的 getAdvisors 方法一样,getAdvice 方法也是在 ReflectiveAspectJAdvisorFactory 类中完成的。

【ReflectiveAspectJAdvisorFactory】

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 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;
		case AtAround:
			springAdvice = new AspectJAroundAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		case AtPointcut:
			if (logger.isDebugEnabled()) {
				logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
			}
			return null;
		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会根据不同的注解生成不同的增强器。后面慢慢介绍。

获取 DeclareParents 注解

DeclareParents 主要用于引介增强的注解形式的实现,而其实现方式与普通增强很类似,只是做了封装。

【ReflectiveAspectJAdvisorFactory】

private Advisor getDeclareParentsAdvisor(Field introductionField) {
	DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class);
	if (declareParents == null) {
		// Not an introduction field
		return null;
	}

	if (DeclareParents.class == declareParents.defaultImpl()) {
		throw new IllegalStateException("'defaultImpl' attribute must be set on DeclareParents");
	}

	return new DeclareParentsAdvisor(
			introductionField.getType(), declareParents.value(), declareParents.defaultImpl());
}

寻找匹配的通知

前面的函数中已经完成了所有的增强的解析,但对于所有增强来讲,并不一定都适用于当前的 Bean,还要挑选出适合的增强,也就是满足我们配置的通配符的增强器。具体实现在 findAdvisorsThatCanApply 中,而且 findAdvisorsThatCanApply 也比上面来的简单的多。

【AbstractAdvisorAutoProxyCreator】

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】

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
	if (candidateAdvisors.isEmpty()) {
		return candidateAdvisors;
	}
	List<Advisor> eligibleAdvisors = new LinkedList<>();
	//首先处理引介增强
	for (Advisor candidate : candidateAdvisors) {
		if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
			eligibleAdvisors.add(candidate);
		}
	}
	boolean hasIntroductions = !eligibleAdvisors.isEmpty();
	for (Advisor candidate : candidateAdvisors) {
		//引介增强已经处理
		if (candidate instanceof IntroductionAdvisor) {
			// already processed
			continue;
		}
		//对于普通bean的处理
		if (canApply(candidate, clazz, hasIntroductions)) {
			eligibleAdvisors.add(candidate);
		}
	}
	return eligibleAdvisors;
}

findAdvisorsThatCanApply 函数的主要功能是寻找所有增强器中适合于当前 class 的增强器。引介增强与普通的增强是处理不一样的,所以分开处理。而对于真正的匹配在 canApply 中实现。

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
	if (advisor instanceof IntroductionAdvisor) {
		return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
	}
	else if (advisor instanceof PointcutAdvisor) {
		PointcutAdvisor pca = (PointcutAdvisor) advisor;
		return canApply(pca.getPointcut(), targetClass, hasIntroductions);
	}
	else {
		// It doesn't have a pointcut so we assume it applies.
		return true;
	}
}

原文 

http://sunliangliang.com/2017/09/07/Spring源码-AOP-七-增强器的获取/

PS:如果您想和业内技术大牛交流的话,请加qq群(527933790)或者关注微信公众 号(AskHarries),谢谢!

转载请注明原文出处:Harries Blog™ » Spring源码-AOP(七)-增强器的获取

赞 (0)

分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址