博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring源码阅读-通用配置实现AOP
阅读量:6419 次
发布时间:2019-06-23

本文共 15818 字,大约阅读时间需要 52 分钟。

hot3.png

前言

如果很多对象需要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......");	}}

这里通过配置一个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
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
beanDefinitions = new ArrayList
(); List
beanReferences = new ArrayList
(); List
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( "
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
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
beanDefinitions, List
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
beanDefinitions, List
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根据具体标签来定:

BEFORE AspectJMethodBeforeAdvice
AFTER AspectJAfterAdvice
AFTER_RETURNING_ELEMENT AspectJAfterReturningAdvice
AFTER_THROWING_ELEMENT AspectJAfterThrowingAdvice
AROUND AspectJAroundAdvice

其他的就是设置一些属性,其中比较重要的就是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
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

你可能感兴趣的文章
页面间通信与数据共享解决方案简析
查看>>
Swift 中 Substrings 与 String
查看>>
作为一个开源软件的作者是一种什么样的感受?
查看>>
移动端适配知识你到底知多少
查看>>
Java基础笔记16
查看>>
TiDB 在 G7 的实践和未来
查看>>
重新认识javascript对象(三)——原型及原型链
查看>>
小学生学“数学”
查看>>
【Vue】组件使用之参数校验
查看>>
FastDFS蛋疼的集群和负载均衡(十七)之解决LVS+Keepalived遇到的问题
查看>>
深入剖析Redis系列(二) - Redis哨兵模式与高可用集群
查看>>
上班第一天的BUG居然是chrome翻译功能导致的
查看>>
Android 用于校验集合参数的小封装
查看>>
iOS混合开发库(GICXMLLayout)七、JavaScript篇
查看>>
instrument 调试 无法指出问题代码 解决
查看>>
理解缓存
查看>>
im也去中心化?Startalk(星语)的去中心化设计之路
查看>>
BAT 经典算法笔试题 —— 磁盘多路归并排序
查看>>
一次完整的HTTP请求
查看>>
Swift 4 前后 KVO 的变化
查看>>