文章导航
目录
文章导航
前言
正文
方法1:parse
方法2:parsePointcut
方法3:createPointcutDefinition
方法4:parseAspect
方法5:isAdviceNode
方法6:parseAdvice
方法7:createAdviceDefinition
方法8:getAdviceClass
总结
前言
本篇文章主要讲解AOP配置中的几个通知类的解析过程,为后续对目标类进行代理做准备;在前面的Spring IOC篇我们讲解了自定义配置的解析,AOP配置的解析过程也是其自定义注解的过程,如果不熟悉自定义解析过程可以看之前的文章
正文
先看下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配置标签,<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; }
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详解
方法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); //判断是否是通知配置标签,如<aop:after>、<aop:before> 等 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; } //封装切面类为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个通知对象如下:
总结
AOP自定命名空间解析会往beanFactory工厂中注册AspectJAwareAdvisorAutoProxyCreator类型的beanDefinition,对于aspect标签的解析中,会将< aop:after >等元素解析成advisor对象的beanDefition,为后续AOP代理增强做准备。