Spring源碼-AOP(七)-整合AspectJ

Spring AOP 源碼解析系列,建議你們按順序閱讀,歡迎討論java

  1. Spring源碼-AOP(一)-代理模式
  2. Spring源碼-AOP(二)-AOP概念
  3. Spring源碼-AOP(三)-Spring AOP的四種實現
  4. Spring源碼-AOP(四)-ProxyFactory
  5. Spring源碼-AOP(五)-ProxyFactoryBean
  6. Spring源碼-AOP(六)-自動代理與DefaultAdvisorAutoProxyCreator
  7. Spring源碼-AOP(七)-整合AspectJ

Spring AOP的實現已經臻於很是完善,而經過與AspectJ的整合使得AOP的使用簡單且靈活。不管是XML仍是註解,都實現了非侵入式的控制。而基於自動代理的基礎上,整合的AspectJ也經過BeanPostProcessor擴展的方式實現細粒度的切面控制。XML方式經過以aop:config標籤實現配置,註解方式則經過@Aspect聲明切面類。兩種方式底層的實現異曲同工,都是基於自動代理的基類AbstractAutoProxyCreator來完成。node

Spring的組件經過XML配置進行註冊以及初始化,其方式就是實現特定命名空間的NamespaceHandler接口,對於Spring+AspectJ的整合方式的XML配置,是從AopNamespaceHandler開始。其中註冊了兩個標籤,config和aspectj-autoproxy,分別爲XML配置的根標籤,和註解方式的啓用配置。spring

registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());

不一樣的解析器對應的處理最終實現了XML或註解方式的AspectJ AOP。chrome

1.XML配置

先看一個XML配置的demoexpress

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
	http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
	
	<!-- 原始對象 -->
	<bean id="chromeBrowser" class="com.lcifn.spring.aop.bean.ChromeBrowser"/>
	<!-- 環繞加強對象 -->
	<bean id="aspectjBrowserAroundAdvice" class="com.lcifn.spring.aop.advice.AspectJBrowserAroundAdvice"></bean>
	
	<!-- aspectj aop 配置 -->
	<aop:config proxy-target-class="true">
		<aop:pointcut id="browserPointcut" expression="execution(* com.lcifn.spring.aop.bean.*.*(..))"/>
		<aop:aspect ref="aspectjBrowserAroundAdvice">
			<aop:around method="aroundIntercept" pointcut-ref="browserPointcut"/>
		</aop:aspect>
	</aop:config>
</beans>

ConfigBeanDefinitionParser解析器用來處理XML配置,Spring的代碼大多使用命名清晰的子方法來描述主結構。數組

ConfigBeanDefinitionParser.java

public BeanDefinition parse(Element element, ParserContext parserContext) {
	CompositeComponentDefinition compositeDef =
			new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
	parserContext.pushContainingComponent(compositeDef);

	// 配置自動代理建立,基於AbstractAutoProxyCreator實現切面的發現和匹配
	configureAutoProxyCreator(parserContext, element);

	List<Element> childElts = DomUtils.getChildElements(element);
	for (Element elt: childElts) {
		String localName = parserContext.getDelegate().getLocalName(elt);
		// aop:pointcut標籤解析
		if (POINTCUT.equals(localName)) {
			parsePointcut(elt, parserContext);
		}
		// aop:advisor標籤解析
		else if (ADVISOR.equals(localName)) {
			parseAdvisor(elt, parserContext);
		}
		// aop:aspect標籤解析
		else if (ASPECT.equals(localName)) {
			parseAspect(elt, parserContext);
		}
	}

	parserContext.popAndRegisterContainingComponent();
	return null;
}

parse方法的主要內容分爲兩部分,自動代理配置的建立以及代理XML配置的解析,能夠從上面代碼中很清晰的看出。緩存

自動代理配置的建立

自動代理配置是基類AbstractAutoProxyCreator的子類AspectJAwareAdvisorAutoProxyCreator,來實現AspectJ相關的AOP的實現。其主要的類結構以下:性能優化

  • AbstractAutoProxyCreator:基於BeanPostProcessor擴展完成AOP代理的建立
  • AbstractAdvisorAutoProxyCreator:切面的發現和匹配
  • AspectJAwareAdvisorAutoProxyCreator:AspectJ相關支持

而configureAutoProxyCreator方法則完成了自動代理配置的初始化。ide

private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
	AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}

由工具類AopNamespaceUtils實現函數

AopNamespaceUtils.java

public static void registerAspectJAutoProxyCreatorIfNecessary(
		ParserContext parserContext, Element sourceElement) {
	// 註冊AspectJ自動代理建立類
	BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
			parserContext.getRegistry(), parserContext.extractSource(sourceElement));
	// 設置proxyTargetClass和exposeProxy屬性
	useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
	registerComponentIfNecessary(beanDefinition, parserContext);
}

對於AspectJ自動代理建立類的註冊有一個優先級機制,即當前容器中已存在自動代理建立類的bean,則以優先級高的替換優先級低的。

AopConfigUtils.java

public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
	return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}

private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	// 存在同名的AUTO_PROXY_CREATOR
	if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
		BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
		if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
			int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
			int requiredPriority = findPriorityForClass(cls);
			// 傳入的優先級高於原有的,則替換BeanDefinition的className
			if (currentPriority < requiredPriority) {
				apcDefinition.setBeanClassName(cls.getName());
			}
		}
		return null;
	}
	// 不存在同名,則建立新的BeanDefinition
	RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
	beanDefinition.setSource(source);
	beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
	beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
	return beanDefinition;
}

對於自動代理建立類的優先級,在Spring中定義了三個

// 基礎版
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
// XML配置	
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
// 註解配置
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);

於是同時存在XML和註解時,註解的自動代理建立類會覆蓋XML的。但AnnotationAwareAspectJAutoProxyCreator實際上是AspectJAwareAdvisorAutoProxyCreator的子類,在查詢候選Advisor時,會先調用父類的方法獲取XML配置中的Advisor。

另外aop:config能夠配置proxy-target-class和expose-proxy,經過useClassProxyingIfNecessary方法設置到AspectJAwareAdvisorAutoProxyCreator的BeanDefinition的屬性中。

AopNamespaceUtils.java

private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
	if (sourceElement != null) {
		boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
		if (proxyTargetClass) {
			AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
		}
		boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
		if (exposeProxy) {
			AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
		}
	}
}

代理XML配置的解析

註冊完自動代理建立類,接下來就是aop的具體配置。經常使用的通常是aop:pointcutaop:aspect兩個標籤,aop:advisor一般在外部aop:config外存在advice配置時使用。

對pointcut的解析比較簡單,就是獲取id及expression屬性,而後建立pointcut的BeanDefinition。

ConfigBeanDefinitionParser.java

private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
	String id = pointcutElement.getAttribute(ID);
	String expression = pointcutElement.getAttribute(EXPRESSION);

	AbstractBeanDefinition pointcutDefinition = null;

	try {
		this.parseState.push(new PointcutEntry(id));
		pointcutDefinition = createPointcutDefinition(expression);
		pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));

		String pointcutBeanName = id;
		if (StringUtils.hasText(pointcutBeanName)) {
			parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
		}
		else {
			pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
		}

		parserContext.registerComponent(
				new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
	}
	finally {
		this.parseState.pop();
	}

	return pointcutDefinition;
}

主要來看下對aspect的解析,在aop:aspect中的有兩類子標籤,一種是pointcut切入點的配置,一種是advice加強的配置,而advice又分爲前置加強,後置加強,環繞加強等。

ConfigBeanDefinitionParser.java	

private void parseAspect(Element aspectElement, ParserContext parserContext) {
	String aspectId = aspectElement.getAttribute(ID);
	String aspectName = aspectElement.getAttribute(REF);

	try {
		this.parseState.push(new AspectEntry(aspectId, aspectName));
		List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
		List<BeanReference> beanReferences = new ArrayList<BeanReference>();

		// 解析引入加強
		List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
		for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
			Element declareParentsElement = declareParents.get(i);
			beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
		}

		// We have to parse "advice" and all the advice kinds in one loop, to get the
		// ordering semantics right.
		NodeList nodeList = aspectElement.getChildNodes();
		boolean adviceFoundAlready = false;
		for (int i = 0; i < nodeList.getLength(); i++) {
			Node node = nodeList.item(i);
			if (isAdviceNode(node, parserContext)) {
				if (!adviceFoundAlready) {
					adviceFoundAlready = true;
					if (!StringUtils.hasText(aspectName)) {
						parserContext.getReaderContext().error(
								"<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
								aspectElement, this.parseState.snapshot());
						return;
					}
					beanReferences.add(new RuntimeBeanReference(aspectName));
				}
				// 解析advice加強,組裝BeanDefinition
				AbstractBeanDefinition advisorDefinition = parseAdvice(
						aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
				beanDefinitions.add(advisorDefinition);
			}
		}

		AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
				aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
		parserContext.pushContainingComponent(aspectComponentDefinition);

		// 解析pointcut標籤
		List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
		for (Element pointcutElement : pointcuts) {
			parsePointcut(pointcutElement, parserContext);
		}

		parserContext.popAndRegisterContainingComponent();
	}
	finally {
		this.parseState.pop();
	}
}

對advice加強的解析parseAdvice方法是核心部分,而其返回的是組裝好的Advisor切面BeanDefinition

ConfigBeanDefinitionParser.java	

private AbstractBeanDefinition parseAdvice(
		String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
		List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

	try {
		this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));

		// create the method factory bean
		// 用來獲取切面類中的加強方法Method對象的工廠bean
		RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
		methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
		methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
		methodDefinition.setSynthetic(true);

		// create instance factory definition
		// 用來獲取切面類對象的工廠bean
		RootBeanDefinition aspectFactoryDef =
				new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
		aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
		aspectFactoryDef.setSynthetic(true);

		// register the pointcut
		// 根據不一樣的加強標籤建立不一樣的加強BeanDefinition
		AbstractBeanDefinition adviceDef = createAdviceDefinition(
				adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
				beanDefinitions, beanReferences);

		// configure the advisor
		// 建立AspectJPointcutAdvisor,封裝上面建立的AdviceBeanDefinition
		RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
		advisorDefinition.setSource(parserContext.extractSource(adviceElement));
		advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
		if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
			advisorDefinition.getPropertyValues().add(
					ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
		}

		// register the final advisor
		parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);

		return advisorDefinition;
	}
	finally {
		this.parseState.pop();
	}
}

此方法中先建立了兩個合成的BeanDefinition,一個爲加強方法的工廠,一個爲切面對象的工廠,用來最終經過反射調用時使用。然後根據不一樣的advice標籤(aop:before,aop:after-returning等)建立相應的加強BeanDefinition,最後使用AspectJPointcutAdvisor封裝加強BeanDefinition而後返回。

再來看看對advice標籤的解析createAdviceDefinition方法

private AbstractBeanDefinition createAdviceDefinition(
		Element adviceElement, ParserContext parserContext, String aspectName, int order,
		RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
		List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

	// 建立advice的BeanDefinition,獲取advice對應的Class對象
	RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
	adviceDefinition.setSource(parserContext.extractSource(adviceElement));

	adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
	adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);

	// after-returning的returning屬性解析
	if (adviceElement.hasAttribute(RETURNING)) {
		adviceDefinition.getPropertyValues().add(
				RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
	}
	// after-throwing的throwing屬性解析
	if (adviceElement.hasAttribute(THROWING)) {
		adviceDefinition.getPropertyValues().add(
				THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
	}
	// arg-names參數暱稱屬性解析
	if (adviceElement.hasAttribute(ARG_NAMES)) {
		adviceDefinition.getPropertyValues().add(
				ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
	}

	// 建立AdviceBeanDefinition構造函數
	ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
	// 構造函數設置加強方法工廠
	cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);

	// 構造函數設置pointcut
	Object pointcut = parsePointcutProperty(adviceElement, parserContext);
	if (pointcut instanceof BeanDefinition) {
		cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
		beanDefinitions.add((BeanDefinition) pointcut);
	}
	else if (pointcut instanceof String) {
		RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
		cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
		beanReferences.add(pointcutRef);
	}

	// 構造函數設置切面對象工廠
	cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);

	return adviceDefinition;
}

不一樣的Advice標籤對應不一樣的Advice類,但都繼承同一個基類AbstractAspectJAdvice。AbstractAspectJAdvice定義了構造函數

public AbstractAspectJAdvice(
	Method aspectJAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory) {
}

建立Advice的BeanDefinition時,即按照此構造函數組裝BeanDefinition中的ConstructorArgumentValues屬性。

而對於不一樣的advice則經過getAdviceClass方法匹配對應的Class

private Class<?> getAdviceClass(Element adviceElement, ParserContext parserContext) {
	String elementName = parserContext.getDelegate().getLocalName(adviceElement);
	if (BEFORE.equals(elementName)) {
		return AspectJMethodBeforeAdvice.class;
	}
	else if (AFTER.equals(elementName)) {
		return AspectJAfterAdvice.class;
	}
	else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {
		return AspectJAfterReturningAdvice.class;
	}
	else if (AFTER_THROWING_ELEMENT.equals(elementName)) {
		return AspectJAfterThrowingAdvice.class;
	}
	else if (AROUND.equals(elementName)) {
		return AspectJAroundAdvice.class;
	}
	else {
		throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
	}
}

至此,每一個Advice都設置了切入點,切面類以及加強方法,再由AspectJPointcutAdvisor對Advice進行封裝,在每一個bean初始化以後,AspectJAwareAdvisorAutoProxyCreator的基類AbstractAutoProxyCreator實現了BeanPostProcessor擴展,查詢全部的匹配bean的Advisor,並建立bean對應的Proxy代理,在方法真正執行時,觸發其相應的Advice執行。

2.註解配置

不管是經過<aop:aspectj-autoproxy/>仍是@EnableAspectJAutoProxy配置的AspectJ註解支持,都是經過AnnotationAwareAspectJAutoProxyCreator支撐對AspectJ相關注解的解析和註冊。AnnotationAwareAspectJAutoProxyCreator繼承AnnotationAwareAspectJAutoProxyCreator,並覆蓋了查詢全部候選Advisor的方法findCandidateAdvisors。基於此方法對@Aspect的切面類進行解析,並生成相應Advisor對象返回。

AnnotationAwareAspectJAutoProxyCreator.java

protected List<Advisor> findCandidateAdvisors() {
	// Add all the Spring advisors found according to superclass rules.
	// 調用父類方法,兼容XML和註解並存
	List<Advisor> advisors = super.findCandidateAdvisors();
	// Build Advisors for all AspectJ aspects in the bean factory.
	// 解析註解方式的切面
	advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
	return advisors;
}

核心操做交由BeanFactoryAspectJAdvisorsBuilder類的buildAspectJAdvisors方法實現

BeanFactoryAspectJAdvisorsBuilder.java

public List<Advisor> buildAspectJAdvisors() {
	List<String> aspectNames = null;

	synchronized (this) {
		// 緩存aspectName
		aspectNames = this.aspectBeanNames;
		if (aspectNames == null) {
			List<Advisor> advisors = new LinkedList<Advisor>();
			aspectNames = new LinkedList<String>();
			// 獲取全部spring容器中的bean
			String[] beanNames =
					BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
			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
				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) {
						// 建立Aspect實例工廠
						MetadataAwareAspectInstanceFactory factory =
								new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
						// 根據Aspect實例工廠獲取全部Advisor對象
						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<Advisor>();
	// 若是aspectNames不爲空,則從緩存中獲取對應的Advisor
	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;
}

核心方法是根據Aspect實例工廠獲取全部Advisor對象

ReflectiveAspectJAdvisorFactory.java

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {
	final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass();
	final String aspectName = maaif.getAspectMetadata().getAspectName();
	validate(aspectClass);

	// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
	// so that it will only instantiate once.
	// 懶加載裝飾類封裝Aspect實例工廠
	final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
			new LazySingletonAspectInstanceFactoryDecorator(maaif);

	final List<Advisor> advisors = new LinkedList<Advisor>();
	for (Method method : getAdvisorMethods(aspectClass)) {
		// 返回有Advice類型(@Before,@AfterReturning等)的註解方法生成的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鏈最前增長一個前置攔截器,用來初始化切面類
		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方法執行具體的操做

ReflectiveAspectJAdvisorFactory.java

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aif,
		int declarationOrderInAspect, String aspectName) {

	validate(aif.getAspectMetadata().getAspectClass());

	// 獲取pointcut切入點expression表達式對象
	AspectJExpressionPointcut ajexp =
			getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass());
	if (ajexp == null) {
		return null;
	}
	// 實例化Advisor對象,支持懶加載策略
	return new InstantiationModelAwarePointcutAdvisorImpl(
			this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName);
}

Advisor對應的Advice對象的實例化實際發生在InstantiationModelAwarePointcutAdvisorImpl的構造方法中

public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp,
		MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) {

	this.declaredPointcut = ajexp;
	this.method = method;
	this.atAspectJAdvisorFactory = af;
	this.aspectInstanceFactory = aif;
	this.declarationOrder = declarationOrderInAspect;
	this.aspectName = aspectName;

	if (aif.getAspectMetadata().isLazilyInstantiated()) {
		// Static part of the pointcut is a lazy type.
		Pointcut preInstantiationPointcut =
				Pointcuts.union(aif.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, aif);
		this.lazy = true;
	}
	else {
		// A singleton aspect.
		// 實例化Advice
		this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
		this.pointcut = declaredPointcut;
		this.lazy = false;
	}
}

private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
	return this.atAspectJAdvisorFactory.getAdvice(
			this.method, pcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
}

經過ReflectiveAspectJAdvisorFactory工廠類完成

public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp,
		MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName) {

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

	// 獲取方法上的AspectJ註解
	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;

	// 根據不一樣AspectJ註解生成對應的Advice對象
	switch (aspectJAnnotation.getAnnotationType()) {
		case AtBefore:
			springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif);
			break;
		case AtAfter:
			springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif);
			break;
		case AtAfterReturning:
			springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif);
			AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterReturningAnnotation.returning())) {
				springAdvice.setReturningName(afterReturningAnnotation.returning());
			}
			break;
		case AtAfterThrowing:
			springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif);
			AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
				springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
			}
			break;
		case AtAround:
			springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif);
			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...
	// 配置Advice對象
	springAdvice.setAspectName(aspectName);
	springAdvice.setDeclarationOrder(declarationOrderInAspect);
	String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
	if (argNames != null) {
		springAdvice.setArgumentNamesFromStringArray(argNames);
	}
	springAdvice.calculateArgumentBindings();
	return springAdvice;
}

至此,註解方式的切面類中的每一個Advice方法生成對應的Advice對象,並被InstantiationModelAwarePointcutAdvisor實現類封裝而後返回。

相比於XML配置的方式,註解方式的Advisor不會生成BeanDefinition註冊到Spring容器中,而是直接返回到Advisor集合中,並以aspectName的方式進行緩存防止重複生成及性能優化。

對於Spring+AspectJ的方式,其主要操做都在於Advisor的解析和生產,底層經過Spring自動代理的方式被Spring容器初始化bean時調用。而AOP代理則是使用ProxyFactory,根據不一樣配置決定JDK或CGLIB的方式來生成。

Spring AOP的四種實現中四種方式,其實也是Sping AOP的演進的過程,而對這四種方式源碼的解析,也證實了高級特性都是基於基礎功能實現的。但願藉由這四種方式的源碼解析,可以對Spring AOP的原理可以有深刻的理解,期待你們的交流!

相關文章
相關標籤/搜索