compile-flow 快速开始

499 阅读2分钟

介绍

compileflow是一个非常轻量、高性能、可集成、可扩展的流程引擎。

compileflow Process引擎是淘宝工作流TBBPM引擎之一,是专注于纯内存执行,无状态的流程引擎,通过将流程文件转换生成java代码编译执行,简洁高效。当前是阿里业务中台交易等多个核心系统的流程引擎。

compileflow能让开发人员通过流程编辑器设计自己的业务流程,将复杂的业务逻辑可视化,为业务设计人员与开发工程师架起了一座桥梁。

引入maven依赖

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.10.1</version>
</dependency>

使用

在springboot环境下使用,springboot相关的依赖这里省略了。

安装插件

compile-flow提供了IDEA的插件,安装插件后可以在IDEA中可视化编辑流程。

编写bpm文件

<?xml version='1.0' encoding='UTF-8'?>
<bpm code="bpm.ktvExample" name="ktv example" type="process" description="ktv example">
  <var name="price" description="支付价格" dataType="java.lang.Integer" inOutType="return"/>
  <var name="totalPrice" description="实付价" dataType="java.lang.Integer" inOutType="inner"/>
  <var name="pList" description="人员" dataType="java.util.List&lt;java.lang.String>" inOutType="param"/>
  <end id="11" name="结束" tag="好的" g="101,549,30,30"/>
  <autoTask id="12" name="付款" g="72,469,88,48">
    <transition to="11" g=":-15,20"/>
    <action type="spring-bean">
      <actionHandle bean="mockSpringBean" clazz="com.example.occ.mock.MockSpringBean" method="payMoney">
        <var name="p1" description="价格" dataType="java.lang.Integer" contextVarName="price" inOutType="param"/>
      </actionHandle>
    </action>
  </autoTask>
  <scriptTask id="9" name="原价" g="132,389,88,48">
    <transition to="12" g=":-15,20"/>
    <action type="ql">
      <actionHandle expression="price*1">
        <var name="price" description="价格" dataType="java.lang.Integer" contextVarName="totalPrice" inOutType="param"/>
        <var name="price" description="价格" dataType="java.lang.Integer" contextVarName="price" inOutType="return"/>
      </actionHandle>
    </action>
  </scriptTask>
  <decision id="8" name="计算费用" g="72,309,88,48">
    <transition to="9" priority="1" name="不超过300" g=":-15,20"/>
    <transition to="10" priority="2" name="超过300" expression="totalPrice>=300" g=":-15,20"/>
    <action type="java">
      <actionHandle clazz="com.example.occ.mock.MockJavaClazz" method="calPrice">
        <var name="p1" description="人数" dataType="java.lang.Integer" contextVarName="pList.size()" inOutType="param"/>
        <var name="p2" description="价格" dataType="java.lang.Integer" contextVarName="totalPrice" inOutType="return"/>
      </actionHandle>
    </action>
  </decision>
  <loopProcess id="13" name="循环节点" collectionVarName="pList" variableName="p" indexVarName="i" variableClass="java.lang.String" startNodeId="13-1" endNodeId="13-1" g="20,75,198,190">
    <transition to="8" g=":-15,20"/>
    <autoTask id="13-1" name="每人唱一首歌" g="50,80,88,48">
      <action type="spring-bean">
        <actionHandle bean="mockSpringBean" clazz="com.example.occ.mock.MockSpringBean" method="sing">
          <var name="p1" dataType="java.lang.String" contextVarName="p" inOutType="param"/>
        </actionHandle>
      </action>
    </autoTask>
  </loopProcess>
  <start id="1" name="开始" tag="223" g="105,17,30,30">
    <transition to="13" g=":-15,20"/>
  </start>
  <note id="14" comment="外框为循环节点" visible="true" g="273,82,93,55">
    <transition to="13" g=":-15,20"/>
  </note>
  <scriptTask id="10" name="9折优惠" g="12,389,88,48">
    <transition to="12" g=":-15,20"/>
    <action type="ql">
      <actionHandle expression="(round(price*0.9,0)).intValue()">
        <var name="price" description="价格" dataType="java.lang.Integer" contextVarName="totalPrice" inOutType="param"/>
        <var name="price" description="价格" dataType="java.lang.Integer" contextVarName="price" inOutType="return"/>
      </actionHandle>
    </action>
  </scriptTask>
</bpm>

在IDEA中通过切换tab可以展示对应的流程

image.png

引入其他相关的类,这几个类文件是必须的,bpm中引用了这几个类

BpmInitializer.class

/**
 * 注意:这里是想让系统启动时,预先加载bpm流程到内存,防止第一次调用时,初始化流程所带来的耗时
 *
 * @author xuan
 * @since 2020/8/16
 */
@Component
@Configuration
public class BpmInitializer implements InitializingBean, ApplicationContextAware {
    @Override
    public void afterPropertiesSet() throws Exception {
        ProcessEngine processEngine = ProcessEngineFactory.getProcessEngine();
        processEngine.preCompile("bpm.ktv.ktvExample");
        processEngine.preCompile("bpm.cal.sqrt");
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringApplicationContextProvider.applicationContext = applicationContext;
    }
}

MockJavaClazz.class

public class MockJavaClazz {
    public int calPrice(int num) {
        System.out.println("total price: " + 30 * num);
        return 30 * num;
    }
    public double sqrt(double a) {
        return Math.sqrt(a);
    }
}

MockSpringBean.class

@Component("mockSpringBean")
public class MockSpringBean {
    public void sing(String name) {
        System.out.println(name + " is singing");
    }
    public void payMoney(int price) {
        System.out.println("actually paid money: " + price);
    }
}

安装插件后,右键单击,会有创建测试代码的选项,创建测试代码如下:

@SpringBootTest
//与junit4配合使用
//@RunWith(SpringRunner.class)
public class KtvExampleFlow_TEST{
    @Test
    public void testProcess() throws Exception {
        String code = "bpm/ktvExample";
        ProcessEngine engine = ProcessEngineFactory.getProcessEngine();
        System.out.println(engine.getJavaCode(code));
        Map<String, Object> context = new HashMap<String, Object>();
        context.put("pList", Arrays.asList("Person-1", "Person-2"));
        try {
            System.out.println(engine.execute(code, context));
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行后的效果如下:

Person-1 is singing
Person-2 is singing
total price: 60
actually paid money: 60
{price=60}

Process finished with exit code 0