精华内容
下载资源
问答
  • 一级流程框架
    千次阅读
    2020-06-21 08:10:11

    上一篇文章我们讲了《实战项目:设计实现一个流程编排框架(分析)》主要对流程编排框架产生的背景,并做了需求分析,这其中包含功能性需求和非功能性需求,算是在正式开始设计之前做一个铺垫。

    前面提到,项目实战分为分析、设计、实现、测试几个部分讲解,其中分析环节跟面向对象分析很相似,都是做需求梳理。但是在时间项目中设计和实现就不是这么一回事了这里的“设计”指的是系统设计,主要是划分模块,对模块进行设计。

    我们主要分为模型定义、流程加载、流程解析、集成使用这四个模块,来说明编排框架的设计思路,今天讲解的重点是,如何通过合理的设计,实现一个易用,易扩展,灵活,延迟低,高容错等非功能需求的编排框架。

    模型定义

    框架需要定义出服务模型,包括请求参数、输出参数、临时变量,流程定义,节点定义,这几个元素。

    • 请求参数:流程需要定义一个输入参数的基类,在开发的过程中请求参数DTO需要继承这个DTO;

    • 输出参数:流程需要定义一个输出参数的基类,在开发的过程中响应参数DTO需要继承这个DTO;

    • 临时变量:用于在流程执行过程中做上下文管理,包括EL表达式解析变量和流程之间参数扭转;

    • 流程定义:需要定义流程标识ID用于标识流程,流程名称用于定义流程别名,请求参数用于定义流程统一输入DTO,输出参数用于定义流程统一响应DTO,临时变量用于上下文管理,流程描述用于描述整个流程的作用,流程节点用于所有节点以Map的形式保存;

    • 节点定义:需要定义节点ID用于标识节点,节点名称用于定义节点别名,请求参数用于定义流程统一输入DTO,输出参数用于定义流程统一响应DTO,节点描述用于描述整个流程的作用,节点类型用于不同的节点类型包括方法节点、bean节点、服务节点、条件节点等,下一个节点标识用过递归的形式执行节点,组件内容,具体指向执行的节点。

    这几个模型直接的关系是怎么样的?整个流程模型是一个包含关系,流程定义 = 请求参数+输出参数+临时变量+节点定义+自定义属性;节点定义 = 请求参数+输出参数+自定义属性;我们在日常开发的过程中需要定义请求参数和输出参数分别集成请求参数和输出参数的基类,通过配置文件加载流程定义,也就是说运行期阶段我们只会用到流程定义模型。定义如下:

    name: openAccount
    id: test
    desc: 条件执行
    input: com.service.flow.sample.common.model.TestInput
    output: com.service.flow.sample.common.model.TestOutput
    temp: com.service.flow.sample.common.model.TestTemp
    startNode: node1
    nodes:
      - node:
          id: node1
          name: methodInvoke
          component: com.service.flow.sample.common.component.TestComponent:test1
          desc: 单节点执行
          input: com.service.flow.sample.common.model.TestInput
          type: method
          next: node2
      - node:
          id: node2
          name: beanInvoke
          component: testComponent:test2
          desc: 单节点执行
          input: com.service.flow.sample.common.model.TestInput
          type: bean
          next: node3
      - node:
          id: node3
          name: conditionByAge
          component: age>20:node4,age<20:node5
          desc: 单节点执行
          type: condition
      - node:
          id: node4
          name: beanInvoke
          component: testComponent:test4
          desc: 单节点执行
          input: com.service.flow.sample.common.model.TestInput
          type: bean
      - node:
          id: node5
          name: beanInvoke
          component: testComponent:test5
          desc: 单节点执行
          input: com.service.flow.sample.common.model.TestInput
          type: bean

    流程加载

    首先我们要确定流程的几个来源有可能是定义的yml、properties、xml、json或者接口;那我我们设计就要支持流程模式可扩展,不管通过什么方式初始化模型,只要能够转换成流程定义,不管什么方式都是可以,完全用到可扩展的需求;

    当然我们也会提供默认的流程加载方式,我们这里以yml格式举例,首先我们需要定义一个yml流程文件,示例如下,新增一个test.flow.yml文件,为了考虑文件路径自定义,也需要把扫描包做成可配置的功能,模式是classpath:flow/*.flow.yml;

    平台首先需要定义定一个流程注册接口,所用加载流程模型用于实现流程注册,在通过平台的机制把流程模型加载到流程管理器,具体实现类我们需要对定义的yml流程就行解析,当然规范要严格按照yml的格式定义;在加载的过程中要有异常处理机制,比如定义的节点和参数不存在,重复定义流程;每一个模型的异常处理完全由平台统一管控。

    考虑到编写流程文件的便利性,需要提供一种机制需要把所有的DTO和基础组件在应用初始化的过程中加载到组件模型,在定义流程文件的时候不需要定义全路径,而且通过注册的bean映射到具体的实现组件,这样的编排文件就变的更加简单了。

    流程解析

    我们把节点分为方法节点、bean节点、服务节点、条件节点、循环节点、子流程节点,我们来讲一下主要的设计;

    第一步:拿到流程ID,在定义的流程上下文获取流程模型,如果获取不到对应的流程,则抛出对应的异常;

    第二步:处理主流程,处理主流程我们需要执行过程就行计时处理,通过解析请求参数和输出参数,上下文并实例化成对象;加载所有的流程节点,并开始查到第一个定义的流程节点;

    第三步:节点解析,根据定义的type类型,我们可以知道需要那种节点解析器去做处理;

    第四步:节点处理,方法节点很简单通过反射机制调用基础组件;bean节点比方法节点多了一次bean到类的映射,也是通过反射执行组件;条件节点通过EL表达式进行匹配,可配置多个条件,既满足if else场景,也需要满足when case场景;服务节点需要我们自定义实现sdk定义一个轻量级框架,不依赖任务容器,需要在starter模块实现等;

    第五步:流程节点执行完成之后会获取下一个节点,然后通过递归的形式调用,有多少节点就递归调用多少次,直到没有下一个节点标识;

    第六步:统计执行情况,包括耗时,响应参数;

    第七步:异常处理机制,全局可自定义异常处理机制,当流程发生异常时回滚操作;

    集成使用

    我们参考Spring框架,低侵入松耦合设计思想。编排框架也应该满足这个设计思想。因为框架是需要集成到应用中使用的,我们希望框架尽可能低侵入,与业务代码松耦合,替换、删除起来也更容易些。我们基于Spring框架做集成,并提供starter依赖组件。

    更多相关内容
  • APQC流程框架体系

    2018-07-19 19:26:18
    一级流程:价值链,是公司最高级别流程。每一个方框代表一个流程链。业务流程链是指一组联系紧密并行/串行的流程。 二级流程:流程链,是对一级流程模块的流程组合。每个方框代表一组流程,又称“流程簇”。 三级...
  • 土地一级开发政企合作框架协议及操作流程.doc
  • 轻量级流程编排框架liteFlow

    万次阅读 多人点赞 2021-01-23 19:43:52
    前言 在每个公司的系统中,总有一些拥有复杂业务逻辑的系统,这些系统承载着核心业务逻辑,几乎每个需求都和这些核心业务有关,...如要灵活改变业务流程的顺序,则要进行代码大改动进行抽象,重新写方法。实时热变更

    前言

    在每个公司的系统中,总有一些拥有复杂业务逻辑的系统,这些系统承载着核心业务逻辑,几乎每个需求都和这些核心业务有关,这些核心业务业务逻辑冗长,涉及内部逻辑运算,缓存操作,持久化操作,外部资源调取,内部其他系统RPC调用等等。时间一长,项目几经易手,维护的成本得就会越来越高。各种硬代码判断,分支条件越来越多。代码的抽象,复用率也越来越低,各个模块之间的耦合度很高。一小段逻辑的变动,会影响到其他模块,需要进行完整回归测试来验证。如要灵活改变业务流程的顺序,则要进行代码大改动进行抽象,重新写方法。实时热变更业务流程?几乎很难实现。

    开源解决方案

    说到流程引擎,开源界有大名鼎鼎的老牌开源软件JBPM,也有近几年非常流行的Activiti和Flowable。他们都是基于BPM协议,可以做到基于角色任务的流传,逻辑的流转。并且很多基于BPM协议的编辑工具都能做可视化的编辑。

    但今天我要介绍的,是一款轻量级的流程编排框架——Liteflow。

    Liteflow主要致力于逻辑驱动的编排。可以满足于大部分的生产业务场景。和以上著名的开源流程引擎相比,虽然不如他们那么全面,但是胜在轻量,高性能和极少的学习成本。而且这些项目都是国外开源项目,集成起来相对比较重,文档本地化也做的不够好。Liteflow拥有完善的本地文档和使用范例。能帮助你的核心系统变得更加灵活,更加易扩展。是一个解耦你系统的利器。

    铂赛东/liteFlow

    Liteflow框架的作用

    Liteflow就是为解耦复杂逻辑而生,如果你要对复杂业务逻辑进行新写或者重构,用liteflow最合适不过。它是一个轻量,快速的组件式流程引擎框架,组件编排,帮助解耦业务代码,让每一个业务片段都是一个组件。

    使用Liteflow,你需要去把复杂的业务逻辑按代码片段拆分成一个个小组件,并定义一个规则流程配置。这样,所有的组件,就能按照你的规则配置去进行复杂的流转。同时Liteflow支持规则文件的热加载,即时完成修改生效。并提供多种持久化规则的方式的扩展。

    Liteflow的设计原则

    Liteflow是基于工作台模式进行设计的,何谓工作台模式?

    n个工人按照一定顺序围着一张工作台,按顺序各自生产零件,生产的零件最终能组装成一个机器,每个工人只需要完成自己手中零件的生产,而无需知道其他工人生产的内容。每一个工人生产所需要的资源都从工作台上拿取,如果工作台上有生产所必须的资源,则就进行生产,若是没有,就等到有这个资源。每个工人所做好的零件,也都放在工作台上。

    这个模式有几个好处:

    • 每个工人无需和其他工人进行沟通。工人只需要关心自己的工作内容和工作台上的资源。这样就做到了每个工人之间的解耦和无差异性。
    • 即便是工人之间调换位置,工人的工作内容和关心的资源没有任何变化。这样就保证了每个工人的稳定性。
    • 如果是指派某个工人去其他的工作台,工人的工作内容和需要的资源依旧没有任何变化,这样就做到了工人的可复用性。
    • 因为每个工人不需要和其他工人沟通,所以可以在生产任务进行时进行实时工位更改:替换,插入,撤掉一些工人,这样生产任务也能实时的被更改。这样就保证了整个生产任务的灵活性。

    这个模式映射到Liteflow框架里,工人就是组件,工人坐的顺序就是流程配置,工作台就是上下文,资源就是参数,最终组装的这个机器就是这个业务。正因为有这些特性,所以Liteflow能做到统一解耦的组件和灵活的装配。

    springboot里快速配置

    Liteflow支持了springboot的自动装配,当然Liteflow也为非springboot和非spring的项目也提供了支持,这里仅以springboot项目为示例进行介绍:

    依赖最新的依赖包:

    <dependency>
      <groupId>com.yomahub</groupId>
      <artifactId>liteflow-spring-boot-starter</artifactId>
      <version>2.3.3</version>
    </dependency>
    

    配置上规则路径:

    liteflow.rule-source=config/flow.xml
    

    定义组件

    Liteflow希望用户把复杂逻辑拆分成一个个可复用的组件,所以你得定义你的组件,组件的定义很简单,你需要继承NodeComponent类,然后实现process 方法就行,以下为示例:

    @Component("test")
    public class TestComponent extends NodeComponent {
    
     @Override
     public void process() {
      Slot slot = this.getSlot();//slot为这个请求的上下文
      //这里为你的业务处理逻辑
     }
    }
    

    这里会有童鞋问,我的业务方法需要入参和出参怎么办,如何传递呢?

    Liteflow为每个线程都自动分配了唯一的一个slot,可以理解为上下文。想一想上面说的那个模型,每个组件不需要和其他组件进行信息互通,所需要的参数从slot里取就是了,同时,执行完业务逻辑之后,把结果也放入slot里。所以每个组件都是独立的无参构造,这样就消除了每个组件的差异性。

    这里的slot能贯穿所有组件,每一个组件都可以访问到slot里所有的数据。当然每个请求之间的slot,Liteflow做了严格的隔离,不用担心数据会串的问题。

    Liteflow提供的默认Slot是一个弱类型的对象,这里建议使用者自己定义一个值对象,只需要继承AbsSlot类,便可成为你自己的Slot。更加贴合业务。

    组件除了必须要实现的process 方法,还有几个可选实现:

    isAccess:表示是否进入该节点,可以用于业务参数的预先判断

    isContinueOnError:表示出错是否继续往下执行下一个组件,默认为false

    isEnd:表示是否立即结束整个流程 ,默认为false,也可以在业务日志里根据业务判断来调用this.setIsEnd(true)来结束整个流程。

    @Component("test")
    public class TestComponent extends NodeComponent {
    
     @Override
     public void process() {
      Slot slot = this.getSlot();//slot为这个请求的上下文
      //这里为你的业务处理逻辑
     }
      
      @Override
     public boolean isAccess() {
      Slot slot = this.getSlot();
      //这里做你的参数检查,如果没获取到必须的业务参数,就不会进入该组件
      boolean checkResult = true;//模拟检查结果为true
      return checkResult;
     }
      
      @Override
     public boolean isContinueOnError() {
      return super.isContinueOnError();//默认为false
     }
      
      @Override
     public boolean isEnd() {
      return super.isEnd();//默认为false
     }
    }
    

    你只需定义你的业务组件,之后,在启动时,Liteflow会自动扫描到你定义的所有组件,并进行加载。

    编辑规则文件

    实现完了组件之后,你需要定义规则文件,之前规则文件的路径配置在了config/flow.xml中,所以我们要编辑这个文件。

    Liteflow的规则文件定义非常简单好理解。简单的配置,但是能覆盖大部分的应用场景。

    先来看一个示例:

    <chain name="chain1">
        <then value="a,c"/> 
        <when value="b,d"/> 
        <then value="e,f,g"/>
    </chain>
    

    在Liteflow中,定义了then和when两种线程执行方式,then代表串行,上面的示例中,c必须要等a执行完才能执行。when代表并行,上面的示例中,b,d同时执行。并且b,d都执行完了,下面的e,f,g才能挨个顺序执行。

    再来看个稍微复杂点的:

    <chain name="chain1">
       <then value="a,c(b|d)"/> 
       <then value="e,f,g"/>
    </chain>
    

    Liteflow提供了条件组件,这种节点的职责就是路由,根据业务逻辑来路由到b节点还是d节点。

    条件组件的定义示例如下,需要去继承NodeCondComponent这个类,最终返回的b就是最终要路由到的节点

    @Component("c")
    public class CComponent extends NodeCondComponent {
    
     @Override
     public String processCond() throws Exception {
        //你的业务逻辑
      return "b";
     }
    }
    

    Liteflow允许你编辑嵌套的流程,例子如下:

    <chain name="chain1">
      <then value="a,c,strategy1,g"/>
    </chain>
    
    <chain name="strategy1">
      <then value="m(m1|m2|strategy2)"/>
    </chain>
    
    <chain name="strategy2">
      <then value="q,p(p1|p2)"/>
    </chain>
    

    在这个例子中,这3条链路是串起来执行的,在xml里,可以写你的组件id,也可以写流程id。配合之前的例子,是不是能表达的流程就更加丰富了点呢。

    以上3个例子涵盖了Liteflow最主要的功能,当然Liteflow还提供一些其他的特性,比如如何进行循环执行,如何打印步骤,并且Liteflow还提供了一个简易的监控模块,用于统计你的组件执行情况。这里就不一一介绍了。具体你可以点击Liteflow的Gitee主页进行查看:

    铂赛东/liteFlow

    示例工程

    为了方便用户的使用,Liteflow在项目里提供了一个测试用例,你可以直接拿来跑:

    同时作者还做了一个带简单业务的示例工程,来演示如何具体实践:

    liteflow-example: liteflow的一个业务示例工程https://gitee.com/bryan31/liteFlow

    这个简单业务是一个电商场景的价格计算的案例,如何通过拆分组件来组合不同的影响价格的业务。并且这个示例工程还提供了一个简单的页面供大家进行调试:

    最后

    在流程编排开源上,国内一直没有特别著名的开源项目。Liteflow的体量虽然无法和业界著名的流程引擎相比,但是在某些场景,的确提供了轻量级的解决方案。并且Liteflow经过了公司生产大流量业务的考验,在稳定性和性能方面有一定保障。希望Liteflow这个开源框架能帮助到有这方面业务需要的同学们。

    关于我

    展开全文
  • Activiti进阶()--工作流(流程框架

    万次阅读 多人点赞 2018-07-18 22:54:50
    Activiti是个项目的名称,Alfresco软件在2010年5月17日宣布Activiti业务流程管理(BPM)开源项目的正式启动,其首席架构师由业务流程管理BPM的专家 Tom Baeyens担任。 Activiti项目是项新的基于Apache许可的...

    工作流

    Activiti是一个项目的名称,Alfresco软件在2010年5月17日宣布Activiti业务流程管理(BPM)开源项目的正式启动,其首席架构师由业务流程管理BPM的专家 Tom Baeyens担任。

    Activiti项目是一项新的基于Apache许可的开源BPM平台,从基础开始构建,旨在提供支持新的BPMN 2.0标准,包括支持对象管理组(OMG),面对新技术的机遇,诸如互操作性和云架构,提供技术实现。

    创始人Tom Baeyens是JBoss jBPM的项目架构师,以及另一位架构师Joram Barrez,一起加入到创建Alfresco这项首次实现Apache开源许可的BPMN 2.0引擎开发中来。

     

    Activiti是一个独立运作和经营的开源项目品牌,并将独立于Alfresco开源ECM系统运行。 Activiti将是一种轻量级,可嵌入的BPM引擎,而且还设计适用于可扩展的云架构。 Activiti将提供宽松的Apache许可2.0,以便这个项目可以广泛被使用,同时促进Activiti BPM引擎和的BPMN 2.0的匹配,该项目现正由OMG通过标准审定。

     

    Activiti官方主页:http://www.activiti.org/index.html

    下载:http://www.activiti.org/download.html

    用户指南:http://activiti.org/userguide/index.html (用户指南来学习Activiti)

    在线API文档: http://activiti.org/javadocs/index.html (开发的时候参阅)

     

    其实简单的来说工作流就是将需要完成某个流程的各个任务组合起来,实现自动化的去完成这些任务,优点就是它实现了工作流程的自动化并且大大提高企业的运作效率;

    它具体的实现过程就是:

    当然最先应该做的就是创建项目导入依赖:

    <!--添加Activiti工作流的支持 一般需要exclusions -->
    <dependency>
      <groupId>org.activiti</groupId>
      <artifactId>activiti-engine</artifactId>
      <version>5.19.0.2</version>
    </dependency>
    <!--添加Activiti工作流对Spring的支持-->
    <dependency>
      <groupId>org.activiti</groupId>
      <artifactId>activiti-spring</artifactId>
      <version>5.19.0.2</version>
    </dependency>
    <dependency>
      <groupId>org.activiti</groupId>
      <artifactId>activiti-bpmn-model</artifactId>
      <version>5.19.0.2</version>
    </dependency>

    <!-- mysql驱动:根据数据库的版本选择驱动版本 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.34</version>
    </dependency>

    1.使用插件画工作图

     

    Idea当中加入插件之后,画如下的流程图:

    整个图的信息:

     

     

    请假节点的信息:

    Name是这个任务的名称“:

    Assignee是执行这个任务的人,此处的意思就是项目经理要请假,其实项目经理这个地方是个变量,设置成为变量的意思就是任何人都可以,而不是只是在这儿设置的项目经理了,当然为了方便理解我们就这样做了;

     

    然后就是审批节点的信息:

    任务是审批,审批的人是总监

     

    然后我们将我们创建的这个文件leave.bpmn赋值一份 然后将其后缀给为xml

    然后我们可以看到配置信息:

    除了头文件以及小编下面截取出来的,其余的都是坐标信息:
    首先是流程节点;
    <process id="myProcess_1" isClosed="false" isExecutable="true" processType="None">
    开始节点
    
      <startEvent id="_2" name="StartEvent"/>
    结束节点
    
      <endEvent id="_3" name="EndEvent"/>
    第一个请假节点且表面请假的人是项目经理
    
      <userTask activiti:assignee="项目经理" activiti:exclusive="true" id="_4" name="请假"/>
    第二个审批节点批准的认时总监
    
      <userTask activiti:assignee="总监" activiti:exclusive="true" id="_5" name="审批"/>
    下面三个就是之前画的流程图中的三条线:2~4、4~6、5~3
    这是于你生成节点的顺序有关的,最先拉经来的胖子在前面这里:
    2是开始
    3是结束
    4是请假
    5是审批
    
      <sequenceFlow id="_6" sourceRef="_2" targetRef="_4"/>
    
      <sequenceFlow id="_7" sourceRef="_4" targetRef="_5"/>
    
      <sequenceFlow id="_8" sourceRef="_5" targetRef="_3"/>
    
    </process>

    以上就是新建的这个bmp文件的xml表示;

     

    2.创建数据库、执行方法

    接下来就测是第一种的到流程引擎的方式

    代码如下:

    @Test
    
    public void shouldAnswerWithTrue()
    
    {
    
        //得到流程引擎的方式一
    
        ProcessEngineConfiguration pec =    ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
    下面是设置数据源
    
        pec.setJdbcUrl("jdbc:mysql://localhost:3306/db_activiti?characterEncoding=utf-8");
    
        pec.setJdbcDriver("com.mysql.jdbc.Driver");
    
        pec.setJdbcUsername("root");
    
        pec.setJdbcPassword("root2");
    设置自动生成表的属性是true, DB_SCHEMA_UPDATE_TRUE它的值就是true
    
        pec.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
    
        ProcessEngine processEngine = pec.buildProcessEngine();

    }

    在执行之前还需要解决一个问题:

    乱码问题:

    Settings—>Editor—>File Encodings utf-8

    idea安装目录bin目录:idea.exe.vmoptions;idea64.exe.vmoptions,在文件末尾添加 -Dfile.encoding=UTF-8 ,然后重启idea

    然后执行这个方法:

    执行的结果:

    然后我们去检查数据库就可以发现它自动生成的表:

     

    5种数据库表说明:

    Activiti的后台是有数据库的支持,所有的表都以ACT_开头。 第二部分是表示表的用途的两个字母标识。用途也和服务的API对应。

    1. ACT_RE_*: 'RE'表示repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
    2. ACT_RU_*: 'RU'表示runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
    3. ACT_ID_*: 'ID'表示identity。 这些表包含身份信息,比如用户,组等等。
    4. ACT_HI_*: 'HI'表示history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
    5. ACT_GE_*: 'GE'表示general。通用数据, 用于不同场景下,如存放资源文件。

    第二种获取流程引擎的方法

    创建核心配置文件,但是配置文件的名字必须是activiti.cfg.xml原因下面会提到:然后使用加载配置文件的方式产生流程引擎,当然我们的表已经生成,此时就不再执行方法,附上代码:

    //得到流程引擎的方式二,加载配置文件
    ProcessEngineConfiguration pec2 = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
    ProcessEngine processEngine1 = pec2.buildProcessEngine();

    第三种获取流程引擎的方法

    //得到流程引擎的方式三,利用底层封装,来加载配置文件,只需要调用方法即可
    ProcessEngine pec3 = ProcessEngines.getDefaultProcessEngine();

    原因就是源码当中有一个init的方法,里面他会自动去加载配置文件:

    这也就是为什么配置文件的名字是固定,不可变的了,因为默认加载的就是这个配置文件,如果你换了配置文件的名字,会报异常

     

     

    以下附上配置文件的代码:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
          
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
          http://www.springframework.org/schema/beans/spring-beans.xsd"
    >

      <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">

    以下是数据源的配置

       <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db_activiti?characterEncoding=utf-8"></property>
            <property name="jdbcDriver" value="com.mysql.jdbc.Driver"></property>
            <property name="jdbcUsername" value="root"></property>
            <property name="jdbcPassword" value="root2"></property>

    以下是自动生成表二设置,和第一种方法的直接设置是一样的
            <property name="databaseSchemaUpdate"    value="true"></property>
        </bean>
     
    </beans>

    3.部署

    在创建完成之后就是部署

    部署流程图就是要将这个流程图部署到流程框架当中去,并且将数据添加到数据库,这个步骤只需要一次即可,因为是可以部署的任务是可以重复使用的,上面执行方法船舰表也是一样,只需要一次即可;

    因为有了配置文件,下面的测试方法当中我们使用的就是第三种方法:

    以下就是我们的部署代码:

    部署我们首先应该得到的就是部署的服务对象

    @Test
    public  void  deploy(){
        ProcessEngine pec=ProcessEngines.getDefaultProcessEngine();

    部署的服务对象
        RepositoryService repositoryService = pec.getRepositoryService();

    部署请假任务:
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("leave.bpmn")
                .name("请假")
                .deploy();

    审批任务会再请假之后自动开启
        System.out.println("请假部署ID"+deploy.getId());
       
    }

    因为是两个任务我们分别部署,在部署完毕之后的输出是:

    然后我们在去看数据库:

    在定义表中(act_re_procdef):

    我们可以很清楚的看到我们定义的任务,它们的key是myProcess_1,也就是我们之前画图时,整个图的ID,可以会看;

    在部署表(act_re_deployment)当中:

    我们可以很清楚的看到我们部署的两个任务请假以及审批

    之后我们去看资源表(act_ge_bytearray):

    我们可以看到我们传到数据库的的资源包括生成的png的图片都在这里,其实生成了以后我们就可以删除我们在项目当中创建的pnm文件了,因为文件以及保存到了数据库所以那些也就没有必要了;

    4.开始任务

    首先我们也必须根据流程引擎对象,来得到我们的运行时服务对象,然后根据我们定义表当中的key来得到流程实例,代码如下:

    @Test
    public void start(){

    根据流程引擎对象得到运行时服务对象:
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();

    根据key得到流程实例
        ProcessInstance myProcess_1 = runtimeService.startProcessInstanceByKey("myProcess_1");
    输出运行时流程实例id以及我们启动的流程它的一个定义id  

     System.out.println("流程实例id"+myProcess_1.getId());
        System.out.println("流程定义ID:"+myProcess_1.getProcessDefinitionId());
    }

    运行之后结果如下:

    流程定义ID我们知道,但是运行时流程id在哪里呢?

    我们来看我们的运行时任务表:

    我们在设立就可以看见我们刚开始的一个任务,就是请假,它的EXECUTION_ID_是2501,而这条任务的id是2504,然后执行的任务name是请假,请假的人是ASSIGNEE_项目经理

    在这里有些读者肯会有疑惑,就是我们部署了两个任务,

    为什么启动了之后就只有请假这一个任务了呢?

    解释一下:原因就是因为Activiti是流程框架,它的节点有特殊性,也就是一个节点的启动是以上一个节点的结束而被触发的,所以在这里当请假这个任务没有完成的时候,审批这个任务是不会出现的,只有当你的请假任务完成了之后,审批的任务就会出现在你运行时的任务表当中,这时你只需要去完成审批的任务即可;

    注意:之前说个我们这里只是以项目经理为例,当这里这里编程变量的时候这里可能会同时出现多个请假的任务,就是多线程,多个请假任务同时进行;

    4.完成任务

    同样完成任务我们首先就要得到我们用来完成任务的服务类,我们是根据运行时任务表当中的id来完成的,具体代码如下:

    @Test
    public void complete(){
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = defaultProcessEngine.getTaskService();

    根据ID完成任务
        taskService.complete("2504");
    }

    完成之后我们去刷新我们的任务表:

    这时候出现的就是我们的审批任务了,由于请假任务的完成审批任务就自动被触发了,所以我们不需要再去启动审批任务,而是由框架自动初发;

    在去看我们的历史记录表(act_hi_actinst)

    由下面的一个图可以看出我们的开始节点在你开始这个任务的时候是跟随开启的任务是一起进来的时间是一样的,而它们的结束时间是不一样的,请假的结束时间就是我们完成请假任务的时间

    而我们完成请假任务的时间恰恰是审批任务的开始时间,而在我们没有完成审批任务之前我们的审批任务是没有结束时间的,因为这个时候它还是待处理此状态;

    此时我们在去完成处于运行时任务表当中的审批任务它的id时5002,代码如下:

    @Test
    public void complete2(){
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = defaultProcessEngine.getTaskService();
        taskService.complete("5002");
    }

    同样我们在去刷新我们的运行时任务表:

    空空如也,所以说我们的审批任务也完成了;

    在这里我们就会发现一个流程框架的机制:

    那就是:当一个任务被开始的时候,它会出现在我们的运行时任务当中,当这个任务完成了,这个任务的记录就会出现在我们的历史记录表当中,而这时运行时任务表时空的,简单的说,其时运行时的几张表充当的就是相当于电脑内存的作用,做个类比它们就是流程框架的内存;

    这时候我们在回过头去看历史记录表:

    此时审批任务也已经完成,而他完成的时间,也正好就是我们结束节点开始的时间,而结束节点可开始节点一样,它们的开和结束时间是一样的,因为它们一旦开始就不会由等待;

    以上就是我们整个流程框架的一个过程,当然我们这里只是以单线程方式来演示的,实际应用当中,往往是多个任务同时进行的,而流程图也比这个复杂的多,所以it之路长漫漫,唯有的是努力+坚持!!!

    版权声明:本文为博主原创文章,未经博主允许不得转载.https://blog.csdn.net/qq_421128

    展开全文
  • 什么是RPC?RPC框架dubbo的核心流程

    万次阅读 多人点赞 2022-01-12 02:48:56
    RPC 是种进程间通信方式,允许像调用本地服务一样调用远程服务,通信协议大多采用二进制方式。RPC 框架的目标就是让远程服务调用更简单、透明,由 RPC 框架负责屏蔽底层的序列化、传输方式和通信的细节,开发者在...

    一、REST 与 RPC:

    1、什么是 REST 和 RPC 协议:

            在单体应用中,各模块间的调用是通过编程语言级别的方法函数来实现,但分布式系统运行在多台机器上,一般来说,每个服务实例都是一个进程,服务间必须使用进程间通信机制来交互,而常见的通信协议主要有 RPC 和 REST 协议。

    (1)REST:

            REST 是基于 HTTP 实现,使用 HTTP 协议处理数据通信,更加标准化与通用,因为无论哪种语言都支持 HTTP 协议。常见的 http API 都可以称为 Rest 接口。REST 是一种架构风格,指一组架构约束条件和原则,满足 REST 原则的应用程序或设计就是 RESTful,RESTful 把一切内容都视为资源。REST 强调组件交互的扩展性、接口的通用性、组件的独立部署、以及减少交互延迟的中间件,它强化安全,也能封装遗留系统。

    (2)RPC:

            RPC 是一种进程间通信方式,允许像调用本地服务一样调用远程服务,通信协议大多采用二进制方式。

    2、RPC 与 REST 的对比:

    类别RPCREST
    报文格式二进制XML、JSON
    网络协议TCP/HTTP/HTTP2HTTP/HTTP2
    序列化开销一般
    网络开销一般
    性能一般
    访问便利性客户端比较方便,但二进制消息不可读文本消息开发者可读,浏览器可访问
    代码耦合度耦合度高松散耦合
    通用性低,对外开发需进一步转换成REST协议高,可直接对外开发
    使用场景内部服务外部服务

    (1)传输协议与性能:RPC 的传输协议灵活,可基于 TCP 实现,由于 TCP 协议处于协议栈的下层,能够更灵活地对协议字段进行定制,让请求报文体积更小,减少网络开销,提高传输性能并缩短传输耗时,实现更大的吞吐量和并发数。REST 的 HTTP 协议是上层协议,发送包含同等内容的信息,请求中会包含很多无用的内容,所占用的字节数比使用 TCP 协议传输更高,因此在同等网络下,HTTP 会比基于 TCP 协议的数据传输效率要低,传输耗时更长,不仅如此,REST 的 HTTP 大部分是通过 JSON 来实现的,序列化也更消耗性能,但如果是基于 HTTP2.0,那么经过封装也是可以作为一个 RPC 来使用的。

    (2)灵活性、开放性与通用性:REST 通过 HTTP 实现,相对更加规范与通用,无论哪种语言都支持 HTTP 协议,所以 REST 的调用和测试都很方便,但使用 RPC 则会有很多约束,而如果 RPC 需要对外开放的话,需要进一步处理,灵活性不如 REST

    (3)使用场景:REST 主要用于对外开放的异构环境,比如浏览器接口调用,Api 接口调用,第三方接口调用等。RPC 主要用于公司内部的服务调用,性能消耗低,传输效率高,特别是大型的网站,内部子系统较多、接口非常多的情况下适合使用 RPC

    二、RPC 框架:

            REST 和 RPC 都常用于微服务架构中,微服务的好处之一,就是不限定服务的提供方使用什么技术选型,能够实现大公司跨团队的技术解耦。 但是,如果没有统一的通信框架,各个团队的服务提供方就需要各自实现一套序列化、反序列化、网络框架、连接池、收发线程、超时处理、状态机等 “业务之外” 的重复技术劳动,造成整体的低效。所以,统一通信框架把上述 “业务之外” 的技术劳动统一处理,是服务化首要解决的问题。

    1、什么是 RPC 框架:

            RPC 框架的目标就是让远程服务调用更简单、透明,由 RPC 框架负责屏蔽底层的序列化、传输方式和通信的细节,开发者在使用时只需要了解谁在什么位置提供了什么样的远程服务接口即可,并不需要关心底层通信细节和调用过程。RPC 框架作为架构微服务化的基础组件,它能大大降低架构微服务化的成本,提高调用方与服务提供方的研发效率。

    2、RPC 框架的技术架构:

            如下图,在典型 RPC 的使用场景中,主要包含了服务发现、负载、容错、网络传输、序列化等组件,其中 ”RPC协议”就指明了服务如何进行序列化和网络传输,这也是RPC的核心功能。

    • 应用级的RPC框架:Dubbo、Google gRPC
    • 通信框架:Netty
    • 远程通信协议:RMI、Socket、SOAP(HTTP XML)、REST(HTTP JSON)

     3、RPC 框架的调用流程:

    3.1、RPC 框架的核心组件:

    (1)客户端(Client):服务调用方。

    (2)客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端。

    (3)服务端存根(Server Stub):接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理。

    (4)服务端(Server):服务的真正提供者。

    3.2、RPC 的调用流程:

    (1)服务消费者(Client 客户端)通过本地调用的方式调用需要消费的服务

    (2)客户端存根(Client Stub)接收到调用请求后负责将方法、入参等信息序列化(组装)成能够进行网络传输的消息体

    (3)客户端存根(Client Stub)找到远程的服务地址,并且将消息通过网络发送给服务端

    (4)服务端存根(Server Stub)收到消息后进行解码,反序列化操作

    (5)服务端存根(Server Stub)根据解码结果调用本地的服务进行相关处理

    (6)服务端(Server)执行具体的业务逻辑,并将处理结果返回给服务端存根(Server Stub)

    (7)服务端存根(Server Stub)将返回结果序列化,并通过网络发送给消费方

    (8)客户端存根(Client Stub)接收到消息,并进行解码与反序列化

    (9)服务消费方得到最终结果;

    而RPC框架的实现目标则是将上面的第2-10步完好地封装起来,也就是把调用、编码/解码的过程给封装起来,让用户感觉上像调用本地服务一样的调用远程服务

    4、如何实现一个RPC框架:

            通过上面几点的介绍,如果要我们实现一个 RPC 框架,我们应该如果做呢?要实现 一个RPC 框架,我们只需要解决的以下几件最基本的事情:

    4.1、如何进行网络通讯:

            远程调用中,客户端和服务端的通讯是基于网络连接的,所以首先需要建立通信连接,通过这个连接把请求信息的字节流传给服务端,然后再把序列化后的响应结果传回客户端,在这个通讯过程中,它所使用的协议是没有限制的,能完成传输就行,但是在这里我们需要考虑两个问题:如何选择网络协议 和 如何建立连接。

    (1)网络协议的选择:多数 RPC 框架选择 TCP 作为传输协议,但其实 UDP 也可以,也有部分选择HTTP,比如 gRPC 使用 HTTP2,但是不同的协议各有优劣势,TCP 更加高效,而 HTTP 在实际应用中更加的灵活,具体需要根据使用场景来选择,下文会介绍如何选择正确的网络传输协议

    (2)通讯连接的建立:RPC 所有交换的数据都在这个连接里传输,这个连接可以是按需连接(需要调用时就先建立连接,调用结束后就立马断掉),也可以是长连接(客户端和服务器建立起连接之后保持长期持有,不管此时有无数据包的发送,可以配合心跳检测机制定期检测建立的连接是否存活有效),多个远程过程调用共享同一个连接。

    4.2、如何那行服务寻址:

            解决寻址的问题,也就是说服务端如何确定客户端要调用的函数,在本地调用中,函数是直接通过函数指针来指定的,但是在远程调用中,函数指针是不行的,因为两个进程的地址空间是完全不一样的。所以在远程调用中,客户端和服务端需要分别维护一个【ID -> 函数】的映射表,ID在所有进程中都是唯一确定的,客户端在做远程过程调用时,附上这个ID,服务端通过查表,来确定客户端需要调用的函数,然后执行相应函数的代码。

            而寻址问题的具体实现方式,则可以通过注册中心,服务提供者完成后,对外暴露相应的功能并将自己注册到注册中心上,接着服务消费者从注册中心寻找服务,然后调用该服务对应的方法完成远程调用

    (1)从服务提供者的角度看:

    • 当服务提供者启动的时候,需要将自己提供的服务注册到指定的注册中心,以便服务消费者能够通过服务注册中心进行查找;
    • 当服务提供者由于各种原因致使提供的服务停止时,需要向注册中心注销停止的服务;服务的提供者需要定期向服务注册中心发送心跳检测,服务注册中心如果一段时间未收到来自服务提供者的心跳后,认为该服务提供者已经停止服务,则将该服务从注册中心上去掉。

    (2)从调用者的角度看:

    • 服务的调用者启动的时候根据自己订阅的服务向服务注册中心查找服务提供者的地址等信息;
    • 当服务调用者消费的服务上线或者下线的时候,注册中心会告知该服务的调用者;
    • 服务调用者下线的时候,则取消订阅。

    4.3、如何序列化和反序列化:

            在本地调用中,我们只需要把参数信息压到内存栈中,然后让函数自己去栈中读取,但是远程过程调用时,客户端跟服务端是不同的进程,不能通过内存来传递参数。所以远程过程调用中,客户端和服务端交互时,方法的参数和结果需要通过底层的网络协议如TCP传递,由于网络协议是基于二进制的(只有二进制数据才能在网络中传输),那么这些值需要序列化成二进制的形式,通过寻址和传输将序列化的二进制发送目标服务器。目标服务器接收到数据时,需要对数据进行反序列化。序列化和反序列化的速度也会影响远程调用的效率。

    • 将对象转换成二进制流的过程叫做序列化
    • 将二进制流转换成对象的过程叫做反序列化

    5、如何选择正确的RPC网络传输协议?

            在 RPC 中可选的网络传输方式有多种,比如 TCP 协议、UDP 协议、HTTP 协议。每一种协议对整体的性能和效率都有不同的影响,那如何选择一个正确的网络传输协议呢?针对这个问题,我们首先要搞明白各种传输协议在 RPC 中的工作方式:

    • 基于 TCP 的协议实现的 RPC 调用,由于 TCP 协议处于协议栈的下层,能够更加灵活地对协议字段进行定制,让请求报文体积更小,减少网络开销,提高传输性能并缩短传输耗时,实现更大的吞吐量和并发数。但是需要更多关注底层复杂的细节,实现的代价更高,同时对不同平台,如安卓,iOS 等,需要重新开发出不同的工具包来进行请求发送和相应解析,工作量大,难以快速响应和满足用户需求。
    • 基于 HTTP 协议实现的 RPC 则可以使用 JSON 和 XML 格式的请求或响应数据,而 JSON 和 XML 作为通用的格式标准(使用 HTTP 协议也需要序列化和反序列化,不过这不是该协议下关心的内容,成熟的 Web 程序已经做好了序列化内容),开源的解析工具已经相当成熟,在其上进行二次开发会非常便捷和简单。但是由于 HTTP 协议是上层协议,发送包含同等内容的信息,请求中会包含很多无用的内容,所占用的字节数比使用 TCP 协议传输更高,因此在同等网络下,HTTP 会比基于 TCP 协议的数据传输效率要低,传输耗时更长,当然压缩数据,能够缩小这一差距。

    三、RPC框架dubbo:

    1、dubbo 是什么?

            前面讲到,RPC 常用于微服务架构中,而 RPC 框架作为架构微服务化的基础组件,能大大降低架构微服务化的成本,提高调用方与服务提供方的研发效率。而 Dubbo 是阿里巴巴开源的基于 Java 的 RPC 分布式服务框架,提供高性能和透明化的 RPC 远程服务调用方案,以及 SOA 服务治理方案。另外,基于 Spring Cloud Alibaba 技术栈的 Spring-cloud-alibaba-dubbo 更是对 dubbo 技术进行了封装,在基于 Spring Cloud Alibaba 提供的 Nacos 注册中心下,提供了 Dubbo 和 Spring Cloud 的整合方案,即 Dubbo Spring Cloud,使得服务内部的 RPC 协议调用几乎是零成本的改造,实现了基于 RPC 的服务调用。

    2、dubbo 的执行流程:

    2.1、dubbo 总体流程:

    • 紫色虚线:启动时完成的功能
    • 蓝色虚线:运行过程中执行的功能,异步调用
    • 蓝色实线:运行过程中执行的功能,同步调用

    2.1.1、dubbo 的总体执行流程说明如下:

    (1)启动容器,加载,运行服务提供者。

    (2)服务提供者在启动时,向注册中心注册自己提供的服务。

    (3)服务消费者在启动时,向注册中心订阅自己所需的服务。

    (4)注册中心返回服务提供者地址列表给消费者,消费者接收到之后,缓存在本地中,如果内容有变更,注册中心将基于长连接推送变更数据给消费者。

    (5)服务消费者,从提供者地址列表中,基于软负载均衡算法,选择一台提供者进行调用,如果调用失败,再选另一台调用。

    (6)服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

    在consumer中使用了代理模式,创建了一个Provider类的一个代理对象。通过代理对象获取Provider中的真实功能,起到保护Provider真实功能的作用。

    2.1.2、dubbo 的整个执行流程可以理解为生产者-消费者模型+注册中心+监控中心,这样设计的原因在于:

    • Consumer 与 Provider 解偶,双方都可以横向增减节点数
    • 注册中心对本身可做对等集群,可动态增减节点,并且任意一台宕掉后,将自动切换到另一台
    • 去中心化,双方不直接依懒注册中心,即使注册中心全部宕机短时间内也不会影响服务的调用
    • 服务提供者无状态,任意一台宕掉后,不影响使用

    2.2、dubbo 同步调用原理:

    2.2.1、dubbo 同步调用流程:

    • (1)客户端线程调用远程接口,向服务端发送请求,同时当前线程应该处于“暂停“状态,即线程不能向后执行了,必需要拿到服务端给自己的结果后才能向后执行
    • (2)服务端接到客户端请求后,处理请求,将结果给客户端
    • (3)客户端收到结果,然后当前线程继续往后执行

            dubbo 中使用了 Socket 来建立长连接、数据传输,而底层结合了的 Apache mina 框架,Apache mina 框架基于Reactor模型通信框架,基于tcp长连接。dubbo 使用 IoSession.write() 方法进行远程调用与发送消息,这个方法的远程调用过程异步的,即对于当前线程来说,将请求发送出来,线程就可以往后执行了,至于服务端的结果,是服务端处理完成后,再以消息的形式发送给客户端的。于是这里出现了2个问题:

    (1)当前线程怎么让它“暂停”,等结果回来后,再向后执行:

            先生成一个对象 obj,在一个全局 map 里 put(ID,obj) 存放起来,再用 synchronized 获取 obj 锁,再调用 obj.wait() 让当前线程处于等待状态,然后另一消息监听线程等到服务端处理结果到来,再 map.get(ID) 找到 obj,再用 synchronized 获取obj锁,再调用 obj.notifyAll() 唤醒前面处于等待状态的线程。

    (2)Socket通信是一个全双工的方式,当有多个线程同时进行远程方法调用,这时 client 与 server 间的 socket 连接上会有很多双方发送的消息传递,前后顺序也可能是乱七八糟的,server处理完结果后,将结果消息发送给client,client收到很多消息,怎么知道哪个消息结果是原先哪个线程调用的:

            使用一个ID,让其唯一,然后传递给服务端,再服务端又回传回来,这样就知道结果是原先哪个线程的了

    2.2.2、dubbo同步调用原理:

    (1)客户端使用一个线程调用远程接口,生成一个唯一 ID,Dubbo 是使用 AtomicLong 从 0 开始累计数字的

    (2)将打包的方法调用信息(如调用的接口名称,方法名称,参数值列表等),和处理结果的回调对象callback,全部封装在一起,组成一个对象object

    (3)向专门存放调用信息的全局 ConcurrentHashMap 里面 put(ID, object)

    (4)将 ID 和打包的方法调用信息封装成一对象 connRequest,使用 IoSession.write(connRequest) 异步发送出去

    (5)当前线程再使用 callback 的 get() 方法试图获取远程返回的结果,在get()内部,则先使用synchronized获取回调对象callback的锁, 检测是否已经获取到结果,如果没有,然后调用 callback 的 wait() 方法,释放 callback 上的锁,让当前线程处于等待状态。

    (6)服务端接收到请求并处理后,将结果(包含了唯一ID)回传给客户端,客户端 socket 连接上专门监听消息的线程收到消息后,分析结果,取到ID,再从前面的 ConcurrentHashMap 里面 get(ID),从而找到 callback,将方法调用结果设置到callback对象里。

    (7)最后监听线程再获取回调对象 callback 的 synchronized 锁(因为前面调用过wait() 导致释放callback的锁),先使用 notifyAll() 唤醒前面处于等待状态的线程继续执行,这样 callback 的 get( )方法继续执行就能拿到调用结果了,至此,整个过程结束

    需要注意的是,这里的callback对象是每次调用产生一个新的,不能共享;另外ID必需至少保证在一个Socket连接里面是唯一的。

    3、dubbo 的负载均衡策略:

    dubbo 的负载均衡策略:https://www.cnblogs.com/wyq178/p/9822731.html

    (1)随机调用策略(默认):随机选择服务器节点,该策略可以对不同服务器实例设置不同的权重,权重越大分配流量越高

    (2)轮询调用策略:均匀地将请求分配到各个机器上。如果各个机器的性能不一样,容易导致性能差的机器负载过高,所以此时需要调整权重,让性能差的机器承载权重小一些,流量少一些。

    (3)最少活跃数策略:根据服务器的运行状态去选择服务,如果某个机器性能越差,那么接收的请求越少,越不活跃,此时就会给不活跃的性能差的机器分配更少的请求

    (4)一致性哈希算法:相同参数的请求一定会被分发到固定的服务器节点。当某个服务器节点挂掉的时候,会基于虚拟节点均匀分配剩余的流量,抖动不会太大。

    4、dubbo 的容错机制:

    Failover(默认):失败自动切换,当出现失败,重试其它服务器,默认为2次。通常用于读操作,但重试会带来更长延迟。

    Failfast:快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。

    Failsafe:失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。

    Failback:失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。

    Forking:并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=”2″ 来设置最大并行数。

    Broadcast:广播调用所有提供者,逐个调用,任意一台报错则报错 。通常用于通知所有提供者更新缓存或日志等本地资源信息。

    5、dubbo支持哪些协议和适用场景:

    (1)dubbo:单一长连接和 NIO 异步通讯,适合大并发小数据量的服务调用,以及消费者远大于提供者的情况。传输协议 TCP,异步 Hessian 序列化。Dubbo 官方推荐使用 dubbo 协议。但是,dubbo 协议不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低

    (2)RMI: 采用 JDK 标准的 RMI 协议实现,使用 Java 标准序列化机制,传输参数和返回参数对象需要实现 Serializable 接口,使用阻塞式短连接,传输数据包大小混合,消费者和提供者个数差不多,可传文件,传输协议 TCP。多个短连接,基于 TCP 协议传输,同步传输,适用常规的远程服务调用和 RMI 互操作。在依赖低版本的 Common-Collections 包,Java 序列化存在安全漏洞。

    (3)WebService:基于 WebService 的远程调用协议,集成 CXF 实现,提供和原生 WebService 的互操作。多个短连接,基于 HTTP 传输,同步传输,适用系统集成和跨语言调用。

    (4)HTTP: 基于 Http 表单提交的远程调用协议,使用 Spring 的 HttpInvoke 实现。多个短连接,传输协议 HTTP,传入参数大小混合,提供者个数多于消费者,需要给应用程序和浏览器 JS 调用。

    (5)Hessian:集成 Hessian 服务,基于 HTTP 通讯,采用 Servlet 暴露服务,Dubbo 内嵌 Jetty 作为服务器时默认实现,提供与 Hession 服务互操作。多个短连接,同步 HTTP 传输,Hessian 序列化,传入参数较大,提供者大于消费者,提供者压力较大,可传文件。

    (6)Redis:基于 Redis 实现的RPC协议。

    (7)Memcache:基于 Memcache实现的 RPC 协议。

    6、dubbo 的通信框架:

    dubbo 默认使用 Netty 作为通讯框架

    7、dubbo的架构设计:

     7.1、图例说明:

    • 左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于中轴线上的为双方都用到的接口。
    • 图中从下至上分为 10 层,各层均为单向依赖,右边的黑色箭头代表层之间的依赖关系,每一层都可以剥离上层被复用,其中,Service 和 Config 层为 API,其它各层均为 SPI。
    • 图中绿色小块的为扩展接口,蓝色小块为实现类,图中只显示用于关联各层的实现类。
    • 图中蓝色虚线为初始化过程,即启动时组装链,红色实线为方法调用过程,即运行时调时链,紫色三角箭头为继承,可以把子类看作父类的同一个节点,线上的文字为调用的方法。

    7.2、各层说明:

    (1)接口服务层(Service):该层与实际业务逻辑相关,根据 provider 和 consumer 的业务设计对应的接口和实现

    (2)配置层(Config):对外配置接口,以 ServiceConfig 和 ReferenceConfig 为中心

    (3)服务代理层(Proxy):服务接口透明代理,生成服务的客户端 Stub 和 服务端的 Skeleton,以 ServiceProxy 为中心,扩展接口为 ProxyFactory

    (4)服务注册层(Registry):封装服务地址的注册和发现,以服务 URL 为中心,扩展接口为 RegistryFactory、Registry、RegistryService

    (5)路由层(Cluster):封装多个提供者的路由和负载均衡,并桥接注册中心,以Invoker 为中心,扩展接口为 Cluster、Directory、Router 和 LoadBlancce

    (6)监控层(Monitor):RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactory、Monitor 和 MonitorService

    (7)远程调用层(Protocal):封装 RPC 调用,以 Invocation 和 Result 为中心,扩展接口为 Protocal、Invoker 和 Exporter

    (8)信息交换层(Exchange):封装请求响应模式,同步转异步。以 Request 和Response 为中心,扩展接口为 Exchanger、ExchangeChannel、ExchangeClient 和 ExchangeServer

    (9)网络 传输 层(Transport):抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel、Transporter、Client、Server 和 Codec

    (10)数据序列化层(Serialize):可复用的一些工具,扩展接口为 Serialization、ObjectInput、ObjectOutput 和 ThreadPool

    dubbo 的架构设计详情推荐阅读官方文档:https://dubbo.apache.org/zh/docs/v2.7/dev/design/


    相关阅读:

    常见的服务器架构入门:从单体架构、EAI 到 SOA 再到微服务和 ServiceMesh

    常见分布式理论(CAP、BASE)和一致性协议(Gosssip协议、Raft一致性算法)

    一致性哈希算法原理详解

    Nacos注册中心的部署与用法详细介绍

    Nacos配置中心用法详细介绍

    SpringCloud OpenFeign 远程HTTP服务调用用法与原理

    什么是RPC?RPC框架dubbo的核心流程

    服务容错设计:流量控制、服务熔断、服务降级

    sentinel 限流熔断神器详细介绍

    Sentinel 规则持久化到 apollo 配置中心

    Sentinel-Dashboard 与 apollo 规则的相互同步

    Spring Cloud Gateway 服务网关的部署与使用详细介绍

    Spring Cloud Gateway 整合 sentinel 实现流控熔断

    Spring Cloud Gateway 整合 knife4j 聚合接口文档

    常见分布式事务详解(2PC、3PC、TCC、Saga、本地事务表、MQ事务消息、最大努力通知)

    分布式事务Seata原理

    RocketMQ事务消息原理


    参考文章:https://juejin.cn/post/6844904127076499463

    展开全文
  • SSM框架的原理和运行流程

    万次阅读 多人点赞 2019-06-30 10:27:05
    SSM框架的工作原理及运行流程SSM框架简介springMVCspringmybatis SSM框架简介 SSM(Spring+SpringMVC+MyBatis)框架集由Spring、MyBatis两个开源框架整合而成(SpringMVC是Spring中的部分内容)。SSM常作为数据源...
  • 设计和实现款轻量的爬虫框架

    千次阅读 2018-01-17 09:44:50
    设计和实现款轻量的爬虫框架 说起爬虫,大家能够想起 Python 里赫赫有名的 Scrapy 框架, 在本文中我们参考这个设计思想使用 Java 语言来实现款自己的爬虫框(lun)架(zi)。 我们从起点一步一步分析...
  • 若依框架后端登录流程

    千次阅读 多人点赞 2021-08-27 16:55:36
    若依框架前后端分离 项目(前端vue,后端 springboot)。 这里只记录后端springboot,前端有疑问可留言! 验证码: 用户进入登录页,请求 /captchaImage 接口获取验证码: 登录 用户点击登录,前端会把...
  • Bsin-PaaS:开源的企业开发框架

    千次阅读 2022-02-10 14:53:14
    Bsin-PaaS(毕昇) 是一套企业的低代码、零代码去中心化应用搭建平台,可帮助企业快速搭建有竞争力的业务中台、流程中台、业务前台。bsin-paas包括微前端设计、微服务框架、服务编排、工作流引擎、安全网关及...
  • mvc高级框架

    千次阅读 2021-06-27 16:32:58
    Spring Web MVC 工作流程Spring MVC请求处理流程Spring MVC九大组件Spring MVC 高级技术拦截器(Interceptor)监听器、过滤器和拦截器对比Servlet过滤器(Filter)监听器(Listener)拦截器(Interceptor)拦截器的...
  • 篇文章了解mvc框架工作流程

    千次阅读 2017-08-25 11:08:09
    动机argo是58同城开源出来的个基于java的轻量mvc框架。这个框架是其13年开源出来源代码,但接下来就没有维护了,但58内部好像还一直维护沿用wf(argo内部称呼)。 但阅读这款轻量级框架源码对于我们理解mvc框架...
  • Vue前端框架

    千次阅读 2022-02-22 09:09:46
    传统的Webpack技术开发的网页流程 传统技术特点: 单击某个链接或按钮,或提交表单后,Webpack页面整体刷新 js/css的请求很多 传统技术缺点: 每次页面整体刷新,都要导致浏览器重新加载对应的内容,特别卡顿 加载的...
  • 直播概念和流程框架

    万次阅读 多人点赞 2016-08-27 22:46:12
    、了解直播 热门直播产品 映客,斗鱼,熊猫,虎牙,花椒等等 1.个完整直播app功能(来自落影loyinglin分享) 1、聊天 私聊、聊天室、点亮、推送、黑名单等; 2、礼物 普通礼物、豪华礼物、红包、排行榜、...
  • 、了解直播 热门直播产品 映客,斗鱼,熊猫,虎牙,花椒等等 1.个完整直播app功能(来自落影loyinglin分享) 1、聊天 私聊、聊天室、点亮、推送、黑名单等;2、礼物 普通礼物、豪华礼物、红包、排行榜、第三...
  • SpringMVC-轻量Web框架

    千次阅读 2016-10-04 16:27:20
    SpringMVC架构 SpringMVC框架个基于请求驱动的Web框架,并且使用了前段控制器模式来进行设计,再根据请求映射规则分发给相应的页面控制器(动作/处理器)进行处理
  • Seam框架非常出色,尤其是他的组件机制设计的很有匠心,真不愧是Gavin King精心打造的框架了,虽然看起来还是有些缺陷,但是做企业应用项目的话,大部分Web应用框架没有集成流行的业务流程和规则引擎,开发人员只能...
  • SSM框架流程及优点

    万次阅读 2020-03-19 03:00:22
    SSM框架 SSM(Spring+SpringMVC+MyBatis)框架集由Spring、MyBatis两个开源框架整合而成(SpringMVC是Spring中的部分内容)。在这个快速发展的互联经济的时代,SSM框架提高了开发人员的工作效率,及时的开发出具有...
  • Java开源工作流框架对比

    千次阅读 2022-02-26 14:59:26
    是对工作流程及其各操作步骤之间业务规则的抽象、概括描述。 在计算机中,工作流属于计算机支持的协同工作(CSCW)的部分。 工作流是复杂版本的状态机 就好比一般的请假流程,小明会先提出请假申请,然后由...
  • Mybatis 的一级缓存和二级缓存详解

    千次阅读 2021-07-31 17:15:59
    注:本笔记是根据尚硅谷的MyBatis视频记录的 ...关于Mybatis的一级缓存和二级缓存执行顺序具体可参考:Mybatis的一级缓存和二级缓存执行顺序  Mybatis整合第三方缓存步骤具体可参考:Myb......
  • Hibernate是个开放源代码的对象关系映射(ORM,Object Rational Mapping)框架,它对JDBC进行了非常轻量的对象封装,它将POJO与数据库表建立映射关系,是个全自动的orm框架,hibernate可以自动生成SQL语句,...
  • 首先说明一下,本系列《SSM项目搭建系列》是为了复习并且完整的熟悉一下SSM框架搭建项目的流程。本系列博客会参照Nimiky...Spring框架个轻量的J2EE框架,同时Spring 是最受欢迎的企业 Java 应用程序开发框架,核
  • 题记 常常听到别人提起:“一级缓存、二级缓存、三级缓存”。那么它们是什么呢?有什么作用呢?
  • 单片机程序框架设计与实现

    千次阅读 2020-09-14 11:10:48
    我们可以将这些共同的地方抽出来形成个固定的程序框架,那么我们再开发新的同种类型的程序时就可以套用这套框架。这样会大大提高我们的开发效率,同时由于这个框架是一套公众的大家都在使用的与维护的,使用它会...
  • VUE前端框架

    千次阅读 2021-11-16 20:12:07
    MVVM框架 入门案例 创建HTML文件,并引入vue.js 练习 Vue的基础语法 –1,运算符&函数 –2,解析类型丰富的data –3,data的三种写法 二,Vue的指令 –1,概述 –2,v-model & v-cloak -3,v-if &...
  • Java框架总结

    万次阅读 多人点赞 2020-01-17 14:14:13
    本系列用来记录常用java...、SSH 1、基本概念 SSH框架是JAVA EE中三种框架所集成,分别是Struts,Spring,Hibernate框架所组成,是当前比较流行的java web开源框架。 集成SSH框架的系统从职责上分为(Struts2--...
  •   我们一般说的Spring框架就是Spring Framework,种轻量级框架,用于提高开发人员的开发效率和可维护性。它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。这些模块包括:核心容器、数据访问/...
  • CUBA - 个卓越的 Java 快速开发框架

    千次阅读 2020-03-25 20:25:00
    个企业快速开发框架CUBA 架构介绍CUBA 框架的能力开箱即用的功能和界面可扩展性其他CUBA 界面预览CUBA Studio付费部分用 CUBA 的好处在哪里节省人力开发积极支持一直在进化中文资源关于作者欢迎使用Markdown编辑...
  • 是 Spring 框架部分,是在 Spring3.0 后发布的。 SpringMVC 优点 基于 MVC 架构 基于 MVC 架构,功能分工明确。解耦合, 容易理解,上手快;使用简单。 就可以开发个注解的 SpringMVC 项目,SpringMVC 也是轻...
  • 产品开发流程概述

    2013-04-23 15:30:16
    公司一级流程框架--4个E2E主业务流程(E2E即端到端的意思)

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 281,027
精华内容 112,410
热门标签
关键字:

一级流程框架