AOP实现之配置文件解析过程(二)

还记得我们在解析IOC时说过的一段代码吗? 相关连接在这里   IOC实现之XML元素解析过程(三)  ,这段代码位于DefaultBeanDefinitionDocumentReader类中,当时我们是这样说的:

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {  
        //如果该元素是默认的命名空间里的元素,所谓默认命名空间,也就是我们在XML中配置的http://www.springframework.org/schema/beans  
        //有可能不是这个命名空间,如果配置了<context:component-scan base-package=""/>   
        //那它的命名空间就是http://www.springframework.org/schema/context  
        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);  
        }  
    }  


再回头看我们的配置文件:

    <aop:config>  
        <aop:aspect ref="aopTargetAdvice">  
        	<!-- 配置增强方法以及切入点 -->
             <aop:before method="beforeInvoke" pointcut="execution(* *.show*(..))"/>  
             <aop:after method="afterInvoke" pointcut="execution(* *.*show*(..))"/>  
        </aop:aspect>  
    </aop:config>
很明显,aop:config这段配置的命名空间不是默认命名空间,而是http://www.springframework.org/schema/aop ,所以代码将会执行delegate.parseCustomElement(ele),OK,我们直接在这里打下断点!

没错吧,读取到的配置就是aop:config!我们来接着解析;

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
		//拿到元素对应的命名空间,这里将拿到http://www.springframework.org/schema/aop
		String namespaceUri = getNamespaceURI(ele);
		//拿到命名空间对应的处理类,这里将拿到org.springframework.aop.config.AopNamespaceHandler
		//关于这个很简单,什么元素名就对应什么命名空间处理类,比如事物tx元素,则对应TxNamespaceHandler类
		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父类NamespaceHandlerSupport中
//在findParserForElement中,将获得具体元素的解析器,<aop:config>的具体元素是config,将会得到ConfigBeanDefinitionParser类,
//所有的元素解析器都实现了BeanDefinitionParser类的parse()方法;
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
	return findParserForElement(element, parserContext).parse(element, parserContext);
}
//如下方代码所示,每个命名空间处理器在实例化时都将初始化好内部的一系列的元素解析器
public class AopNamespaceHandler extends NamespaceHandlerSupport {
	private final Map<String, BeanDefinitionParser> parsers =
			new HashMap<String, BeanDefinitionParser>();
	@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());
	}
	protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
		this.parsers.put(elementName, parser);
	}
}


接着解析:

public BeanDefinition parse(Element element, ParserContext parserContext) {
		CompositeComponentDefinition compositeDef =
				new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
		parserContext.pushContainingComponent(compositeDef);
	
		//配置并创建好AspectJAwareAdvisorAutoProxyCreator类
		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);
			}
			//我们配置的是aop:aspect ,解析步骤将进入这里
			else if (ASPECT.equals(localName)) {
				parseAspect(elt, parserContext);
			}
		}

		parserContext.popAndRegisterContainingComponent();
		return null;
	}
	
	private void parseAspect(Element aspectElement, ParserContext parserContext) {
		String aspectId = aspectElement.getAttribute(ID);
		String aspectName = aspectElement.getAttribute(REF);//得到我们配置好的aopTargetAdvice

		try {
			//循环遍历所有子元素定义
			NodeList nodeList = aspectElement.getChildNodes();
			boolean adviceFoundAlready = false;
			for (int i = 0; i < nodeList.getLength(); i++) {
				Node node = nodeList.item(i);
				//是否是一个有意义的元素定义,允许定义before,after,after-returning,after-throwing,around这几个元素
				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;
						}
						//将aopTargetAdvice添加到引用bean集合中
						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);

			List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
			for (Element pointcutElement : pointcuts) {
				parsePointcut(pointcutElement, parserContext);
			}

			parserContext.popAndRegisterContainingComponent();
		}
		finally {
			this.parseState.pop();
		}
	}
	
	//解析通知器
	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);

			// 创建一个通知类并配置好切入点,具体将根据我们的配置来创建不同功能的通知类;
			// 我们配置了after和before
			//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;
			//}
			AbstractBeanDefinition adviceDef = createAdviceDefinition(
					adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
					beanDefinitions, beanReferences);

			// 配置并创建好一个AspectJPointcutAdvisor通知器
			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();
		}
	}


上面的代码中spring为我们创建了众多的bean!这些bean随着稍后讲解代理bean的创建,你就能完全明白它们起到的作用了!

我们可以将上面这几串代码总结为spring根据我们的配置,为我们后面Aop的使用和代理bean的创建做了一些准备工作,其核心就是先创建了一个AspectJAwareAdvisorAutoProxyCreator对象,然后根据配置文件循环创建通知器AspectJPointcutAdvisor,我们配置了几个增强方法就会创建几个通知器对象,每个通知器都会包含一个通知Advice,(比如AspectJAfterAdvice或者AspectJMethodBeforeAdvice),同时也会包含一个pointCut切入点对象;


AspectJAwareAdvisorAutoProxyCreator是创建代理bean的入口,由于它实现了BeanPostProcessor接口,所以在一个bean创建完成的时候,它的后处理方法postProcessAfterInitialization将会获得回调,稍候我们会证实这一点,在这个后处理方法中,它将我们原本已经创建好的bean进行替换,替换成一个代理bean;

通知器AspectJPointcutAdvisor的作用就是用来调用通知类Advice(也叫做增强类)的增强方法;

通知Advice的作用自然就是根据pointCut切入点是否匹配来进行方法增强;

稍候我们再细说这些类的作用和调用时机,这里只要有个印象就可以了;


至此,我们已经分析完毕spring对组件的xml解析过程,总结来讲,就是通过命名空间找到命名空间处理类,再通过具体元素找到元素解析器,再调用解析器的parse()进行解析操作,  spring中所有的组件都是这么来解析的,将来我们如果要自己定制spring的扩展功能,完全可以自己定义一个命名空间,编写xsd,并且提供继承了NamespaceHandlerSupport的命名空间处理类,且为每个元素定义好BeanDefinitionParser的解析器实现类,完成parse方法,就可以定制化一个组件功能了!







  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值