Spring AOP 解析

这里不提供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容器注册了一个BeanNameorg.springframework.aop.config.internalAutoProxyCreatorBean
   //根据配置proxy-target-classexpose-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定义beanNameBeanDefinition
   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) {
   //获取idname
   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);

      // 根据织入方式(beforeafter这些)创建RootBeanDefinition,名为adviceDefadvice定义
      //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;
}
回到ConfigBeanDefinitionParser的parseAspect方法:
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));
      //创建PointcutBean定义
      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>标签对应的Beanprototype即原型的
   //<aop:pointcut>标签对应解析出来的BeanDefinitionRootBeanDefinition   // RootBenaDefinitoin中的Classorg.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容器中。


上一篇: DispatcherServlet接收请求

下一篇: Spring AOP 代理

猜你喜欢

转载自blog.csdn.net/m0_37444820/article/details/80810783