Spring AOP源码:配置文件解析过程

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Spring AOP源码:配置文件解析过程

文章导航

Spring AOP:基本概述

Spring AOP源码:配置文件解析过程

Spring AOP源码:配置文件解析过程

Spring AOP源码:拦截器责任链处理过程

目录

文章导航

前言

正文

方法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个通知对象如下:

17f443d31fc202f4444d91ed0109973f_f72d76d930cc4396b109bc96e6b1895c.png

总结

AOP自定命名空间解析会往beanFactory工厂中注册AspectJAwareAdvisorAutoProxyCreator类型的beanDefinition,对于aspect标签的解析中,会将< aop:after >等元素解析成advisor对象的beanDefition,为后续AOP代理增强做准备。


目录
相关文章
|
2天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
2天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
2天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
2天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
26天前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
53 12
|
21天前
|
PyTorch Shell API
Ascend Extension for PyTorch的源码解析
本文介绍了Ascend对PyTorch代码的适配过程,包括源码下载、编译步骤及常见问题,详细解析了torch-npu编译后的文件结构和三种实现昇腾NPU算子调用的方式:通过torch的register方式、定义算子方式和API重定向映射方式。这对于开发者理解和使用Ascend平台上的PyTorch具有重要指导意义。
|
3天前
|
安全 搜索推荐 数据挖掘
陪玩系统源码开发流程解析,成品陪玩系统源码的优点
我们自主开发的多客陪玩系统源码,整合了市面上主流陪玩APP功能,支持二次开发。该系统适用于线上游戏陪玩、语音视频聊天、心理咨询等场景,提供用户注册管理、陪玩者资料库、预约匹配、实时通讯、支付结算、安全隐私保护、客户服务及数据分析等功能,打造综合性社交平台。随着互联网技术发展,陪玩系统正成为游戏爱好者的新宠,改变游戏体验并带来新的商业模式。
|
7月前
|
安全 Java Spring
Spring之Aop的底层原理
Spring之Aop的底层原理
|
7月前
|
设计模式 Java uml
Spring AOP 原理
Spring AOP 原理
41 0
|
4月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现

推荐镜像

更多