Spring源码阅读-通用配置实现AOP

本文详细解析了Spring AOP配置文件加载的过程,包括配置解析、切面定义、通知定义及切点表达式的处理等关键步骤。

前言

如果很多对象需要aop, 按前面一篇每个对象单独配置实现方式太麻烦,spring提供了通用的配置方式,不需要单独指定代理对象。
看个例子:

public class Person implements IPerson {
	private String name;
	public String queryName() {
		System.out.println("name:" + name);
		return name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

public class PersonAdvice {

	public void before() throws Throwable {
		System.out.println("before......");
	}

	public void after() throws Throwable {
		System.out.println("after......");
	}
}
<bean id="person" class="com.myframe.modules.test.service.impl.Person">
	<property name="name" value="zhangsan"></property>
</bean> 
<!-- 准备切点跟advice -->
<bean id="beforeAfterAdvice" class="com.myframe.modules.test.service.impl.PersonAdvice">
</bean>

<aop:config>
	<aop:aspect id="aspect" ref="beforeAfterAdvice">
		<aop:pointcut id="queryPoincut" expression="execution(* com.myframe.modules.test.service.impl.**.query*(..))" />
		<aop:before method="before" pointcut-ref="queryPoincut"/>
		<aop:after method="after" pointcut-ref="queryPoincut"/>
	</aop:aspect>
</aop:config>

这里通过配置一个queryPoincut来匹配满足expression规则对象来实现切面,调用person的query开头的方法会先调用beforeAfterAdvice的before方法,最后调用after方法,如下:

before......
name:zhangsan
after......

 

这里具体expression是怎么匹配的,以及怎么创建代理的先不看,先看这个配置是怎么被spring加载的。

加载配置

下面又是长篇大论的贴代码。。。。。

首先根据标签找到对应的handler, 在AopNamespaceHandler里面定义了标签对应的处理类:

public class AopNamespaceHandler extends NamespaceHandlerSupport {

	/**
	 * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the '
	 * {@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
	 * and '{@code scoped-proxy}' tags.
	 */
	@Override
	public void init() {
		// In 2.0 XSD as well as in 2.1 XSD.
		registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
		registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
		registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

		// Only in 2.0 XSD: moved to context namespace as of 2.1
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
	}
}

这里我们看config的ConfigBeanDefinitionParser的parse方法:

public BeanDefinition parse(Element element, ParserContext parserContext) {
	CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(),
			parserContext.extractSource(element));
	//把创建的复合componet放入栈中
	parserContext.pushContainingComponent(compositeDef);
	// 注册,嵌入到复合component
	configureAutoProxyCreator(parserContext, element);

	// 解析子元素
	List<Element> childElts = DomUtils.getChildElements(element);
	for (Element elt : childElts) {
		String localName = parserContext.getDelegate().getLocalName(elt);
		if (POINTCUT.equals(localName)) {
			parsePointcut(elt, parserContext);
		} else if (ADVISOR.equals(localName)) {
			parseAdvisor(elt, parserContext);
		} else if (ASPECT.equals(localName)) {
			//解析aspect标签
			parseAspect(elt, parserContext);
		}
	}
	//注册整个复合component
	parserContext.popAndRegisterContainingComponent();
	return null;
}

ParserContext中有个栈用于存放复合组件,pushContainingComponent和popAndRegisterContainingComponent是spring对复合组件注册的通用用法,这两步操作中间部分是我们比较关心的内容,

1. configureAutoProxyCreator

    跟踪configureAutoProxyCreator方法调用:

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

public static void registerAspectJAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {
	//把 AspectJAwareAdvisorAutoProxyCreator初始化成BeanDefinition
	BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
			parserContext.getRegistry(), parserContext.extractSource(sourceElement));
	//对proxyTargetClass和exposeProxy判断, 并把值设置到上面的beanDefinition属性中
	useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
	//把beanDefinition创建成BeanComponentDefinition并注册到复合组件中的内部集合
	registerComponentIfNecessary(beanDefinition, parserContext);
}

这里主要三步:创建、设置属性、注册。

1)创建

AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary把自动代理创建器初始化成BeanDefinition,内部会有一些判断逻辑:

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");
	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);
			if (currentPriority < requiredPriority) {
				//如果当前优先级低则改变class
				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;
}

默认使用的代理创建器是AspectJAwareAdvisorAutoProxyCreator,如果已经注册了对应的自动代理创建器并且名字不相同,则比较一下优先级,最终目的就是生成BeanDefinition。

(这里怎么会已经存在自动代理创建器AUTO_PROXY_CREATOR_BEAN_NAME的?这个可以在spring的配置文件中指定,也可以在spring的beanFactory启动后用自定义扩展点手动设置进去,spring的对象工厂就是这么灵活,处处可以设置对象,可以设置任何对象。)

2)设置属性

接着上面useClassProxyingIfNecessary方法,BeanDefinition创建完成后还要对其设置一些属性,这里设置了两个属性:proxyTargetClass和exposeProxy,后面具体用到的时候再看。

3)注册

registerComponentIfNecessary方法是把beanDefinition创建成BeanComponentDefinition,然后注册到前面栈中复合组件的内部集合中。

2. 解析子标签

aop:config下面可以有三子标签(aop:aspect, aop:pointcut, aop:advisor),功能都差不多,只是解析的对象不同而已,这里只以aspect一个流程看其思想。

根据上面的例子来跟踪代码,定位到parseAspect(elt, parserContext)方法:

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;
		//===============================================
		//循环先对advice型节点进行处理
		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;
					}
					//第一次会获取依赖的aspect对象名称
					beanReferences.add(new RuntimeBeanReference(aspectName));
				}
				//创建advisor的BeanDefinition
				AbstractBeanDefinition advisorDefinition = parseAdvice(aspectName, i, aspectElement, (Element) node,
						parserContext, beanDefinitions, beanReferences);
				beanDefinitions.add(advisorDefinition);
			}
		}

		//把上面的aspect生成的beanDefinitions一起生成组件,然后压入栈中
		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节点
private boolean isAdviceNode(Node aNode, ParserContext parserContext) {
	if (!(aNode instanceof Element)) {
		return false;
	} else {
		String name = parserContext.getDelegate().getLocalName(aNode);
		return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name)
				|| AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name));
	}
}
1) advisor

上面代码循环部分对aspect下面的advice标签进行处理,这里的advice标签只包含before, after, after-returning, after-throwing, around,看一下他们是怎么处理,重点跟进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
		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
		RootBeanDefinition aspectFactoryDef = new RootBeanDefinition(
				SimpleBeanFactoryAwareAspectInstanceFactory.class);
		aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
		aspectFactoryDef.setSynthetic(true);

		// register the pointcut
		AbstractBeanDefinition adviceDef = createAdviceDefinition(adviceElement, parserContext, aspectName, order,
				methodDefinition, aspectFactoryDef, beanDefinitions, beanReferences);

		// configure the advisor
		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();
	}
}

这里主要是把before after这些方法转成BeanDefinition后创建一个名为adviceDef的BeanDefinition,看创建方法createAdviceDefinition的实现:

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

	//根据标签获取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);

	if (adviceElement.hasAttribute(RETURNING)) {
		adviceDefinition.getPropertyValues().add(RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
	}
	if (adviceElement.hasAttribute(THROWING)) {
		adviceDefinition.getPropertyValues().add(THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
	}
	if (adviceElement.hasAttribute(ARG_NAMES)) {
		adviceDefinition.getPropertyValues().add(ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
	}
	//构造参数,主要包括三块:METHOD_INDEX、POINTCUT_INDEX、ASPECT_INSTANCE_FACTORY_INDEX
	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;
}

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

adviceDef的class根据具体标签来定:

BEFOREAspectJMethodBeforeAdvice
AFTERAspectJAfterAdvice
AFTER_RETURNING_ELEMENTAspectJAfterReturningAdvice
AFTER_THROWING_ELEMENTAspectJAfterThrowingAdvice
AROUNDAspectJAroundAdvice

其他的就是设置一些属性,其中比较重要的就是ConstructorArgumentValues。

接着上面的parseAdvice方法:创建完adviceDef后再把它作为构造参数创建advisorDefinition,advisorDefinition的class为AspectJPointcutAdvisor,这样一个切面包含的advice和pointcut就在一个advisorDefinition中了, 最后注册到BeanFactory中。

advisorDefinition创建完毕后会一起把他们构造成AspectComponentDefinition复合组件,然后压入栈中,在看一下上面的parseAspect方法:

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

	try {
		//...

		//把上面的aspect生成的beanDefinitions一起生成组件,然后压入栈中
		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();
	}
}
2) pointcut

parseAspect最后解析的标签是pointcut,看一下parsePointcut方法的代码:

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));
		//创建expression对应的BeanDefinition
		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);
		}
		//注册到aspect复合组件内部集合
		parserContext.registerComponent(
				new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
	} finally {
		this.parseState.pop();
	}

	return pointcutDefinition;
}

protected AbstractBeanDefinition createPointcutDefinition(String expression) {
	RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
	beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
	beanDefinition.setSynthetic(true);
	beanDefinition.getPropertyValues().add(EXPRESSION, expression);
	return beanDefinition;
}

创建expression的BeanDefinition并注册到beanFactory中,最后注册到aspect复合组件的内部集合中,这里expression的class是AspectJExpressionPointcut。

 

总结

这篇讲了用配置文件方式配置aop,spring是如何解析加载的,还没有讲到具体如何使用加载的这些BeanDefinition,这个里面一个核心类AspectJAwareAdvisorAutoProxyCreator就是创建动态代理的核心类,他的子类AnnotationAwareAspectJAutoProxyCreator是用注解方式是注册的,它们的上层抽象类AbstractAutoProxyCreator实现了创建代理的核心逻辑。

后面一篇会看一下用@Aspect注解时spring是如何加载的,再下一篇会看AbstractAutoProxyCreator是怎么创建动态代理的。

 

转载于:https://my.oschina.net/chengxiaoyuan/blog/1477107

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值