Spring AOP中是如何注册Advisor的?

前置博文:
Spring AOP中如何为Bean创建代理?
Spring AOP中是如何注册Advisor的?
Spring AOP如何为目标方法创建拦截器链?
Spring AOP拦截器调用的实现
Spring AOP中CGLIB代理对象增强通知执行原理

在前面Spring AOP中如何为Bean创建代理?一文中我们看到创建代理前首先要获取到Advisor设置给ProxyFactory,之后才可进行代理的创建。那么容器中的Advisor是如何实例化并注册的?

这个最开始的入口是在AbstractAutoProxyCreatorpostProcessBeforeInstantiation方法中。

完成对目标方法的切面增强设计(Advice)和关注点的设计(Pointcut)以后,需要一个对象把它们结合起来,完成这个作用的就是Advisor(通知器/顾问器)。通过Advisor,可以定义应该使用哪个通知并在哪个关注点使用它,也就是说通过Advisor,把Advice和Pointcut结合起来,这个结合为使用IOC容器配置AOP应用,或者说即开即用地使用AOP基础设施,提供了便利。

【1】前置流程

如下图所示,在AbstractApplicationContext的refresh方法中会触发registerBeanPostProcessors(beanFactory);进行Bean后置处理器的注册。
在这里插入图片描述

而在AbstractAutowireCapableBeanFactory的createBean过程中,会触发resolveBeforeInstantiation(beanName, mbdToUse);,那么这里就会触发applyBeanPostProcessorsBeforeInstantiation

AbstractAutowireCapableBeanFactory的applyBeanPostProcessorsBeforeInstantiation方法如下所示。

@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
			Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
			if (result != null) {
				return result;
			}
		}
	}
	return null;
}

这里会判断BeanPostProcessor 是否为InstantiationAwareBeanPostProcessor,如果是,则调用其postProcessBeforeInstantiation方法。

InstantiationAwareBeanPostProcessor是BeanPostProcessor的一个子接口,在bean的属性设置或autowire触发前增加before-instantiationafter-instantiation回调。通常用于抑制特定目标bean的默认实例化,例如创建具有特殊TargetSources的代理(池目标、延迟初始化目标等),或实现其他注入策略,如字段注入。

如下所示是其子类实现,这里我们主要分析AbstractAutoProxyCreator。
在这里插入图片描述
如下图所示,AbstractAutoProxyCreator的postProcessBeforeInstantiation会首先对bean进行判断。isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName),前者用来判断是否为基础类,后置用来判断是否需要直接跳过。

当前这只是语义含义,实际上isInfrastructureClass用来判断当前bean是否为Advice、Pointcut、Advisor、AopInfrastructureBean或者(标注了Aspect注解但是bean的field不是以ajc$开头)。
在这里插入图片描述

我们看下shouldSkip方法。这里会调用AspectJAwareAdvisorAutoProxyCreator的shouldSkip方法,如下所示。

@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
	// TODO: Consider optimization by caching the list of the aspect names
	List<Advisor> candidateAdvisors = findCandidateAdvisors();

	//如果advisor是AspectJPointcutAdvisor 且切面名称是beanName则跳过
	for (Advisor advisor : candidateAdvisors) {
		if (advisor instanceof AspectJPointcutAdvisor &&
				((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
			return true;
		}
	}
	
	return super.shouldSkip(beanClass, beanName);
}

//super.shouldSkip(beanClass, beanName); AbstractAutoProxyCreator#shouldSkip
protected boolean shouldSkip(Class<?> beanClass, String beanName) {

	//是否为 original instance
	return AutoProxyUtils.isOriginalInstance(beanName, beanClass);
}

很显然,advisor就是从findCandidateAdvisors方法得到的。

【2】得到Advisor

结合前面流程,这里会走到AnnotationAwareAspectJAutoProxyCreator的findCandidateAdvisors方法。也就说这个方法才是真正获取(实例化)Advisor的方法。

同样,在Spring AOP中如何为Bean创建代理?一文中为Bean创建代理获取Advisor时也会触发该方法。

@Override
protected List<Advisor> findCandidateAdvisors() {
	// Add all the Spring advisors found according to superclass rules.
	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;
}

this.aspectJAdvisorsBuilder =
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);

首先调用父类的findCandidateAdvisors方法,然后使用BeanFactoryAspectJAdvisorsBuilderAdapter创建AspectJAdvisor。

① super.findCandidateAdvisors();

这里是AbstractAdvisorAutoProxyCreator的findCandidateAdvisors方法。

//AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() {
	Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
	return this.advisorRetrievalHelper.findAdvisorBeans();
}
// advisorRetrievalHelper是BeanFactoryAdvisorRetrievalHelperAdapter;

我们跟踪看一下advisorRetrievalHelper是如何找到Advisor的。

public List<Advisor> findAdvisorBeans() {
	// Determine list of advisor bean names, if not cached already.
	// 从缓存里面获取
	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 如internalTransactionAdvisor
		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) {
	// 这里默认返回true
		if (isEligibleBean(name)) {
			// 如果是正在创建的,则跳过
			if (this.beanFactory.isCurrentlyInCreation(name)) {
				if (logger.isTraceEnabled()) {
					logger.trace("Skipping currently created advisor '" + name + "'");
				}
			}
			else {
				try {
				// 从容器中获取Bean
					advisors.add(this.beanFactory.getBean(name, Advisor.class));
				}
				catch (BeanCreationException ex) {
					Throwable rootCause = ex.getMostSpecificCause();
					// ....
					throw ex;
				}
			}
		}
	}
	return advisors;
}

总结来讲该方法就是从容器中找Advisor,如果正在创建则跳过否则就获取到然后返回。

② aspectJAdvisorsBuilder.buildAspectJAdvisors

BeanFactoryAspectJAdvisorsBuilder的buildAspectJAdvisors方法如下所示。我们的切片被包装成Advisor就是在这里实现的。

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<>();
				// 获取到所有的Bean,本文这里有460个
				String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
						this.beanFactory, Object.class, true, false);
				for (String beanName : beanNames) {
 //AnnotationAwareAspectJAutoProxyCreator.isEligibleAspectBean进行判断,默认返回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.
					// 获取beanTYPE
					Class<?> beanType = this.beanFactory.getType(beanName);
					if (beanType == null) {
						continue;
					}
					// 如果当前Bean标注了Aspect注解 且未被ajc编译
					if (this.advisorFactory.isAspect(beanType)) {
						// 放到aspectNames中-包含单例和非单例
						aspectNames.add(beanName);
						AspectMetadata amd = new AspectMetadata(beanType, beanName);
						// 默认就是SINGLETON
						if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
							MetadataAwareAspectInstanceFactory factory =
									new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
							List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
							
							if (this.beanFactory.isSingleton(beanName)) {
							// 如果是单例则放入缓存
								this.advisorsCache.put(beanName, classAdvisors);
							}
							else {
							// 否则放入aspectFactoryCache
								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));
						}
					}
				}
				// 重新给aspectBeanNames 赋值
				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;
}

这里大概分为三种情况:

  • 如果List<String> aspectNames为null,则进行初始化;
  • 如果List<String> aspectNames为空,则直接返回空列表;
  • 否则则尝试从advisorsCache或者advisorFactory获取advisors

那么在第一次是一定为null的,这里会从容器中获取到(标注了Aspect注解 且未被ajc编译的bean),如我们自己定义的logAspect。最终会通过this.advisorFactory.getAdvisors(factory)得到Advisor。

那么这里List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);就是核心部分。

③ ReflectiveAspectJAdvisorFactory.getAdvisors

@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
 // 得到切片类型与名称
	Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
	String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();

	//进行校验 PerClauseKind.PERCFLOW PerClauseKind.PERCFLOWBELOW 是否有注解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<>();
	// 得到AdvisorMethod,即不包含Pointcut的方法
	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.
// PerClauseKind.PERTARGET PerClauseKind.PERTHIS PerClauseKind.PERTYPEWITHIN才会进入
	if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
		Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
		advisors.add(0, instantiationAdvisor);
	}

	// Find introduction fields.
	// 引入通知中,尝试将每一个Field 包装为一个Advisor 
	for (Field field : aspectClass.getDeclaredFields()) {
	// 这里针对的是DeclareParents 会创建DeclareParentsAdvisor
		Advisor advisor = getDeclareParentsAdvisor(field);
		if (advisor != null) {
			advisors.add(advisor);
		}
	}

	return advisors;
}

如上代码所示,这里首先获取切面类中未标注Pointcut注解的方法,然后实例化得到InstantiationModelAwarePointcutAdvisorImpl这样一个Advisor。

然后判断aspect是否需要懒加载,如果是则实例化SyntheticInstantiationAdvisor放入advisors的第一个位置。

最后对引入通知进行处理,拿到那些标注了DeclareParents 注解的filed,得到相应的DeclareParentsAdvisor放入advisors。

至此就完成了advisors 的查找。我们可以跟踪看一下getAdvisor和getDeclareParentsAdvisor方法。

getAdvisor

如下所示,首先进行校验然后获取AspectJExpressionPointcut ,如果不为null则实例化InstantiationModelAwarePointcutAdvisorImpl。这个也是我们在Spring AOP中如何为Bean创建代理?看到的。

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

在实例化InstantiationModelAwarePointcutAdvisorImpl,还会对Advice进行实例化。如下所示在ReflectiveAspectJAdvisorFactory的方法中会拿到方法的AspectJAnnotation,根据其AnnotationType分别创建Advice。

// ReflectiveAspectJAdvisorFactory#getAdvice
@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;
// 根据注解的类型创建对应的Advice
	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;
}
AnnotationTypeAdvice
AtPointcutnull
AtAroundAspectJAroundAdvice
AtBeforeAspectJMethodBeforeAdvice
AtAfterAspectJAfterAdvice
AtAfterReturningAspectJAfterReturningAdvice
AtAfterThrowingAspectJAfterThrowingAdvice

到这里,我们自定义的logAspect如何成为一个Advisor就清晰了。我们再看一下getDeclareParentsAdvisor。


getDeclareParentsAdvisor

这里主要为引入通知解析Advisor 。关于引入通知参考博文Spring中使用AspectJ实现AOP的五种通知

@Nullable
private Advisor getDeclareParentsAdvisor(Field introductionField) {
// 判断DeclareParents注解
	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");
	}

// 实例化DeclareParentsAdvisor
	return new DeclareParentsAdvisor(
			introductionField.getType(), declareParents.value(), declareParents.defaultImpl());
}

【3】如果同时有引入通知呢?

如下所示在切面中添加了引入通知:

@Aspect
@Component
public class LogAspect {

    @DeclareParents(value = "com.recommend.controller.HomeController",defaultImpl=MyDeclareImpl.class)
    private MyDeclareService myDeclareService;
    //...
}    

此时我们获取得到排序的eligibleAdvisors如下所示,DeclareParentsAdvisor排在了第二位。

0 = {ExposeInvocationInterceptor$1@7173} "org.springframework.aop.interceptor.ExposeInvocationInterceptor.ADVISOR"
1 = {DeclareParentsAdvisor@7137} 
2 = {InstantiationModelAwarePointcutAdvisorImpl@7136} "InstantiationModelAwarePointcutAdvisor: expression [logPointCut()]; advice method [public void com.recommend.config.LogAspect.AfterThrowing(org.aspectj.lang.JoinPoint,java.lang.Exception)]; perClauseKind=SINGLETON"
3 = {InstantiationModelAwarePointcutAdvisorImpl@7135} "InstantiationModelAwarePointcutAdvisor: expression [logPointCut()]; advice method [public void com.recommend.config.LogAspect.AfterReturning(org.aspectj.lang.JoinPoint,java.lang.Object)]; perClauseKind=SINGLETON"
4 = {InstantiationModelAwarePointcutAdvisorImpl@7134} "InstantiationModelAwarePointcutAdvisor: expression [logPointCut()]; advice method [public void com.recommend.config.LogAspect.afterMethod(org.aspectj.lang.JoinPoint)]; perClauseKind=SINGLETON"
5 = {InstantiationModelAwarePointcutAdvisorImpl@7132} "InstantiationModelAwarePointcutAdvisor: expression [logPointCut()]; advice method [public java.lang.Object com.recommend.config.LogAspect.around(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable]; perClauseKind=SINGLETON"
6 = {InstantiationModelAwarePointcutAdvisorImpl@7133} "InstantiationModelAwarePointcutAdvisor: expression [execution(* com.recommend.controller.*.*(..))]; advice method [public void com.recommend.config.LogAspect.beforeMethod(org.aspectj.lang.JoinPoint)]; perClauseKind=SINGLETON"

DeclareParentsAdvisor对象如下所示:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

流烟默

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

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

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

打赏作者

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

抵扣说明:

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

余额充值