Spring AOP源码:配置文件解析过程

前言

本篇文章主要讲解AOP配置中的几个通知类的解析过程,为后续对目标类进行代理做准备;在前面的Spring IOC篇我们讲解了自定义配置的解析,AOP配置的解析过程也是其自定义注解的过程,如果不熟悉自定义解析过程可以看之前的文章Spring IOC源码:<context:component-scan>源码详解

正文

先看下AOP配置文件内容:

<?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.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

		<bean id="accountAdvice" class="service.impl.AccountAdvice" ></bean>
		<bean id="myAccount" class="service.impl.MyAccount" ></bean>

		<aop:config>
			<aop:pointcut id="pointCut" expression="execution(* service.impl.*.*())"/>
			<aop:aspect ref="accountAdvice">
				<aop:after method="after" pointcut-ref="pointCut"></aop:after>
				<aop:before method="before" pointcut-ref="pointCut"></aop:before>
				<aop:around method="around" pointcut-ref="pointCut"></aop:around>
				<aop:after-returning method="afterReturn" pointcut-ref="pointCut"></aop:after-returning>
				<aop:after-throwing method="afterThrow" pointcut-ref="pointCut"></aop:after-throwing>
			</aop:aspect>

		</aop:config>


</beans>

回到BeanDefinition的解析步骤中,由于AOP是属于自定义解析,所以会使用自定义命名空间处理器进行处理,也就是会走delegate.parseCustomElement(ele)方法。

	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				if (node instanceof Element) {
					Element ele = (Element) node;
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
					else {
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}
	public BeanDefinition parseCustomElement(Element ele) {
		return parseCustomElement(ele, null);
	}


	/**
	 * Parse a custom element (outside of the default namespace).
	 * @param ele the element to parse
	 * @param containingBd the containing bean definition (if any)
	 * @return the resulting bean definition
	 */
	@Nullable
	public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
		String namespaceUri = getNamespaceURI(ele);
		if (namespaceUri == null) {
			return null;
		}
		//获取自定义命名空间处理器
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)),见方法1详解

方法1:parse

	public BeanDefinition parse(Element element, ParserContext parserContext) {
		BeanDefinitionParser parser = findParserForElement(element, parserContext);
		return (parser != null ? parser.parse(element, parserContext) : null);
	}
public BeanDefinition parse(Element element, ParserContext parserContext) {
		CompositeComponentDefinition compositeDef =
				new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
		parserContext.pushContainingComponent(compositeDef);
		//注册AspectJAwareAdvisorAutoProxyCreator到beanFactory工厂中
		configureAutoProxyCreator(parserContext, element);

		List<Element> childElts = DomUtils.getChildElements(element);
		for (Element elt: childElts) {
			String localName = parserContext.getDelegate().getLocalName(elt);
			//解析POINTCUT配置标签,
			if (POINTCUT.equals(localName)) {
				parsePointcut(elt, parserContext);
			}
			//解析标签
			else if (ADVISOR.equals(localName)) {
				parseAdvisor(elt, parserContext);
			}
			//解析标签
			else if (ASPECT.equals(localName)) {
				parseAspect(elt, parserContext);
			}
		}

		parserContext.popAndRegisterContainingComponent();
		return null;
	}

parsePointcut(elt, parserContext),见方法2详解

parseAspect(elt, parserContext),见方法4详解

方法2:parsePointcut

private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
		//获取id属性值
		String id = pointcutElement.getAttribute(ID);
		//获取expression表达式值
		String expression = pointcutElement.getAttribute(EXPRESSION);

		AbstractBeanDefinition pointcutDefinition = null;

		try {
			this.parseState.push(new PointcutEntry(id));
			//将表达式内容封装成RootBeanDefinition对象
			pointcutDefinition = createPointcutDefinition(expression);
			pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));

			String pointcutBeanName = id;
			if (StringUtils.hasText(pointcutBeanName)) {
				//如果有设置id名称,则将其作为beanName并将definition注册到beanFactory工厂中
				parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
			}
			else {
				//没有名称则生成并注册到beanFactory工厂中
				pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
			}
			//注册组件到上下文中
			parserContext.registerComponent(
					new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
		}
		finally {
			this.parseState.pop();
		}

		return pointcutDefinition;
	}

createPointcutDefinition(expression),见方法3详解

方法3:createPointcutDefinition

	protected AbstractBeanDefinition createPointcutDefinition(String expression) {
		//设置封装类型为AspectJExpressionPointcut的RootBeanDefinition
		RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
		//设置为原型模式
		beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
		beanDefinition.setSynthetic(true);
		//添加属性值
		beanDefinition.getPropertyValues().add(EXPRESSION, expression);
		return beanDefinition;
	}

方法4:parseAspect

private void parseAspect(Element aspectElement, ParserContext parserContext) {
		//获取id值
		String aspectId = aspectElement.getAttribute(ID);
		//获取引用的切面类名称
		String aspectName = aspectElement.getAttribute(REF);

		try {
			this.parseState.push(new AspectEntry(aspectId, aspectName));
			//存放解析的BeanDefinition
			List<BeanDefinition> beanDefinitions = new ArrayList<>();
			List<BeanReference> beanReferences = new ArrayList<>();
			//获取declare-parents标签
			List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
			//遍历解析封装成BeanDefinition
			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(
									" tag needs aspect bean reference via 'ref' attribute when declaring advices.",
									aspectElement, this.parseState.snapshot());
							return;
						}
						//封装切面类为RuntimeBeanReference,并添加到集合中
						beanReferences.add(new RuntimeBeanReference(aspectName));
					}
					//解析当前通知标签
					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);
			//获取aspect标签下的pointcut子标签
			List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
			//解析并注册到beanFactory中
			for (Element pointcutElement : pointcuts) {
				parsePointcut(pointcutElement, parserContext);
			}

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

isAdviceNode(node, parserContext),见方法5详解
parseAdvice(aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences),见方法6详解

方法5:isAdviceNode

private boolean isAdviceNode(Node aNode, ParserContext parserContext) {
		if (!(aNode instanceof Element)) {
			return false;
		}
		else {
			//获取节点名称
			String name = parserContext.getDelegate().getLocalName(aNode);
			//判断是否是befor、after、after-returning、after-throwing、around
			return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name) ||
					AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name));
		}
	}

方法6:parseAdvice

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
			//创建MethodLocatingFactoryBean的RootBeanDefinition 
			RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
			//设置切面名称
			methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
			//设置method方法名称
			methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
			//标志为合成的
			methodDefinition.setSynthetic(true);

			// create instance factory definition
			//创建SimpleBeanFactoryAwareAspectInstanceFactory类型的RootBeanDefinition 
			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
			//将advice再加层封装成advisor
			RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
			advisorDefinition.setSource(parserContext.extractSource(adviceElement));
			advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
			//判断是否有order属性,有则添加到定义信息中
			if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
				advisorDefinition.getPropertyValues().add(
						ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
			}

			// register the final advisor
			//生成beanName并注册到beanFactory中 
			parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);

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

createAdviceDefinition(adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,beanDefinitions, beanReferences),见方法7详解

方法7:createAdviceDefinition

private AbstractBeanDefinition createAdviceDefinition(
			Element adviceElement, ParserContext parserContext, String aspectName, int order,
			RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
			List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
		//获取对应类型的消息通知类并封装成RootBeanDefinition 
		RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
		adviceDefinition.setSource(parserContext.extractSource(adviceElement));
		//添加切面名称
		adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
		//添加declarationOrder值
		adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
		//添加returning属性值
		if (adviceElement.hasAttribute(RETURNING)) {
			adviceDefinition.getPropertyValues().add(
					RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
		}
		//添加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));
		}
		//获取构造函数
		ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
		//添加第一个参数为方法对象
		cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
		//解析其表达式
		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;
	}

getAdviceClass(adviceElement, parserContext),见方法8详解

方法8:getAdviceClass

	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 + "].");
		}
	}

到这里对AOP配置的解析就完成了,我们可以看到解析后的5个通知对象如下:
Spring AOP源码:配置文件解析过程_第1张图片

总结

AOP自定命名空间解析会往beanFactory工厂中注册AspectJAwareAdvisorAutoProxyCreator类型的beanDefinition,对于aspect标签的解析中,会将< aop:after >等元素解析成advisor对象的beanDefition,为后续AOP代理增强做准备。

你可能感兴趣的:(spring,spring,java,后端)