这里不提供AOP的示例了,直接怼源码。
<bean id="testtImpl" class="org.test.aop.TestImpl" />
<bean id="timeHandler" class="org.test.aop.TimeHandler" />
//启用了强制CGLIB代理
<aop:config proxy-target-class="true">
<aop:aspect id="time" ref="timeHandler">
<aop:pointcut id="addAllMethod" expression="execution(* org.test.aop.*(..))" />
<aop:before method="printTime" pointcut-ref="addAllMethod" />
<aop:after method="printTime" pointcut-ref="addAllMethod" />
</aop:aspect>
</aop:config>
1.找到Spring处理AOP的源头
和普通bean一样,只不过在解析aop的时候走的是自定义标签处理,不在累述自定义标签的实现。
代码直接定位到DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法:
//使用 Spring 的 Bean 规则从 Document 的根元素开始进行 Bean 定义的 Document 对象 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { //Bean 定义的 Document 对象使用了 Spring 默认的 XML 命名空间 if (delegate.isDefaultNamespace(root)) { //获取 Bean 定义的 Document 对象根元素的所有子节点 NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); //获得 Document 节点是 XML 元素节点 if (node instanceof Element) { Element ele = (Element) node; //Bean 定义的 Document 的元素节点使用的是 Spring 默认的 XML 命名空间 if (delegate.isDefaultNamespace(ele)) { //使用 Spring 的 Bean 规则解析元素节点 parseDefaultElement(ele, delegate); } else { //没有使用 Spring 默认的 XML 命名空间,则使用用户自定义的解//析规则解析元素节点 delegate.parseCustomElement(ele); } } } } else { //Document 的根节点没有使用 Spring 默认的命名空间,则使用用户自定义的 //解析规则解析 Document 根节点 delegate.parseCustomElement(root); } }
//处理用户自定义标签 @Nullable public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) { //获取命名空间 String namespaceUri = getNamespaceURI(ele); if (namespaceUri == null) { return null; } //根据命名空间找到对应的NamespaceHandler进行解析 NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } //调用自定义的NamespaceHandler进行解析 return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
遇到<aop:config>标签的时候就不一样了,<aop:config>并不是默认的Namespace,因此走自定义标签处理。
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()); } }
自定义标签会调用到这个地方,套路王。不熟悉自定义标签的可以去看看自定义标签。在解析的时候回调用ConfigBeanDefinitionParser
@Override @Nullable public BeanDefinition parse(Element element, ParserContext parserContext) { CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); parserContext.pushContainingComponent(compositeDef); //向Spring容器注册了一个BeanName为org.springframework.aop.config.internalAutoProxyCreator的Bean //根据配置proxy-target-class和expose-proxy,设置是否使用CGLIB进行代理以及是否暴露最终的代理 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); } } parserContext.popAndRegisterContainingComponent(); return null; }
点击configureAutoProxyCreator一直往下,直到这里。
public static void registerAspectJAutoProxyCreatorIfNecessary( ParserContext parserContext, Element sourceElement) { BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary( parserContext.getRegistry(), parserContext.extractSource(sourceElement)); useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); registerComponentIfNecessary(beanDefinition, parserContext); } public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary( ParserContext parserContext, Element sourceElement) { //注册或升级autoproxy定义beanName为BeanDefinition BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary( parserContext.getRegistry(), parserContext.extractSource(sourceElement)); //对于proxy-target-class以及expose-proxy属性处理 useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); //注册组件并通知,便于监听器下一步处理 registerComponentIfNecessary(beanDefinition, parserContext); }
private void parseAspect(Element aspectElement, ParserContext parserContext) { //获取id和name String aspectId = aspectElement.getAttribute(ID); String aspectName = aspectElement.getAttribute(REF); try { this.parseState.push(new AspectEntry(aspectId, aspectName)); List<BeanDefinition> beanDefinitions = new ArrayList<>(); List<BeanReference> beanReferences = new ArrayList<>(); 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; 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; } beanReferences.add(new RuntimeBeanReference(aspectName)); } //1 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); //拿到所有<aop:aspect>下的pointcut标签,进行遍历,由parsePointcut方法进行处理: //5 for (Element pointcutElement : pointcuts) { parsePointcut(pointcutElement, parserContext); } parserContext.popAndRegisterContainingComponent(); } finally { this.parseState.pop(); } }有一个关键的判断就是第22行的ifAdviceNode判断
//循环只用来处理<aop:aspect>标签下的<aop:before>、<aop:after> // 、<aop:after-returning>、<aop:after-throwing method="">、<aop:around method="">这五个标签的。 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)); } }
如果是5个标签里面的一个都会调用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); // 根据织入方式(before、after这些)创建RootBeanDefinition,名为adviceDef即advice定义 //2 AbstractBeanDefinition adviceDef = createAdviceDefinition( adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef, beanDefinitions, beanReferences); //上一步创建的RootBeanDefinition写入一个新的RootBeanDefinition,构造一个新的对象,名为advisorDefinition,即advisor定义 //生成的RootBeanDefinition包装了一下,new一个新的RootBeanDefinition出来,Class类型是org.springframework.aop.aspectj.AspectJPointcutAdvisor //用于判断<aop:aspect>标签中有没有"order"属性的,有就设置一下,"order"属性是用来控制切入方法优先级的。 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)); } //4 // 将advisorDefinition注册到DefaultListableBeanFactory中 parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition); return advisorDefinition; } finally { this.parseState.pop(); } }
创建的AbstractBeanDefinition实例是RootBeanDefinition
private Class<?> getAdviceClass(Element adviceElement, ParserContext parserContext) { //before对应AspectJMethodBeforeAdvice //After对应AspectJAfterAdvice //after-returning对应AspectJAfterReturningAdvice //after-throwing对应AspectJAfterThrowingAdvice //around对应AspectJAroundAdvice 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:before>、<aop:after>两个标签对应的AbstractBeanDefinition就创建出来了。
回到ConfigBeanDefinitionParser类parseAdvice方法:
private AbstractBeanDefinition parseAdvice( String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext, List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) { ..................................... //4 // 将advisorDefinition注册到DefaultListableBeanFactory中 parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition); return advisorDefinition; } finally { this.parseState.pop(); } }
public String registerWithGeneratedName(BeanDefinition beanDefinition) { //获取beanName String generatedName = generateBeanName(beanDefinition); //注册到DefaultListableBeanFactory getRegistry().registerBeanDefinition(generatedName, beanDefinition); return generatedName; }
private void parseAspect(Element aspectElement, ParserContext parserContext) { ...................... AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition( aspectElement, aspectId, beanDefinitions, beanReferences, parserContext); parserContext.pushContainingComponent(aspectComponentDefinition); List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT); //拿到所有<aop:aspect>下的pointcut标签,进行遍历,由parsePointcut方法进行处理: //5 for (Element pointcutElement : pointcuts) { parsePointcut(pointcutElement, parserContext); } parserContext.popAndRegisterContainingComponent(); } finally { this.parseState.pop(); } }拿到所有<aop:aspect>下的pointcut标签,进行遍历,由parsePointcut方法进行处理:
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) { //获取<aop:pointcut>标签下的"id"属性与"expression"属性。 String id = pointcutElement.getAttribute(ID); String expression = pointcutElement.getAttribute(EXPRESSION); AbstractBeanDefinition pointcutDefinition = null; try { //推送一个PointcutEntry,表示当前Spring上下文正在解析Pointcut标签 this.parseState.push(new PointcutEntry(id)); //创建Pointcut的Bean定义 pointcutDefinition = createPointcutDefinition(expression); pointcutDefinition.setSource(parserContext.extractSource(pointcutElement)); //用于注册获取到的Bean定义,默认pointcutBeanName为<aop:pointcut>标签中定义的id属性 String pointcutBeanName = id; //如果<aop:pointcut>标签中配置了id属性 if (StringUtils.hasText(pointcutBeanName)) { parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition); } else { //pointcutBeanName=org.springframework.aop.aspectj.AspectJExpressionPointcut#序号(从0开始累加) pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition); } parserContext.registerComponent( new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression)); } finally { this.parseState.pop(); } return pointcutDefinition; }
第2finally块在<aop:pointcut>标签解析完毕后,表示此次<aop:pointcut>标签解析完毕。
createPointcutDefinition的实现,比较简单:
protected AbstractBeanDefinition createPointcutDefinition(String expression) { //<aop:pointcut>标签对应的Bean是prototype即原型的 //<aop:pointcut>标签对应解析出来的BeanDefinition是RootBeanDefinition, // 且RootBenaDefinitoin中的Class是org.springframework.aop.aspectj.AspectJExpressionPointcut RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class); beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE); beanDefinition.setSynthetic(true); beanDefinition.getPropertyValues().add(EXPRESSION, expression); return beanDefinition; }
这样一个流程下来,就解析了<aop:pointcut>标签中的内容并将之转换为RootBeanDefintion存储在Spring容器中。
下一篇: Spring AOP 代理