Flowable DMN 与 Spring 集成实战:DmnEngineFactoryBean、自动部署与单元测试
2026/9/16 23:21:13 网站建设 项目流程

Flowable DMN 与 Spring 集成实战:DmnEngineFactoryBean、自动部署与单元测试

【免费下载链接】flowable-engineA compact and highly efficient workflow and Business Process Management (BPM) platform for developers, system admins and business users.项目地址: https://gitcode.com/GitHub_Trending/fl/flowable-engine

Flowable 决策引擎(DMN)完全可以在脱离 Spring 的情况下独立运行,但一旦应用需要事务管理、依赖注入或频繁的重启部署场景,Spring 集成带来的收益会非常明显。本篇指南以 Flowable 官方文档 docs/docusaurus/docs/dmn/ch04-Spring.md 为主体,结合仓库中 flowable-dmn-spring 模块的源码实现,系统讲解DmnEngineFactoryBean的 Bean 化配置、deploymentResources自动部署机制与三种deploymentMode策略的取舍,以及基于 JUnit Jupiter 的 Spring 单元测试写法。读完你将能够在 Spring 容器中完整落地 Flowable DMN 的配置、部署与测试链路。

DmnEngineFactoryBean:将 DMN 引擎注册为 Spring Bean

Flowable DMN 的 Spring 集成的起点是org.flowable.dmn.spring.DmnEngineFactoryBean(源码见 DmnEngineFactoryBean.java)。它实现了 Spring 的FactoryBean<DmnEngine>接口:接收一个 DMN 引擎配置对象,调用dmnEngineConfiguration.buildDmnEngine()完成引擎构建,并把构建出的DmnEngine作为单例 Bean 暴露给容器。

由于引擎的创建与属性配置逻辑仍然完全沿用 DMN 配置章节 中定义的方式,Spring 集成不需要引入任何新的配置概念——你只需要把原本的StandaloneDmnEngineConfiguration换成 Spring 版本,其余配置项(数据源、数据库 schema 更新策略、IDM 集成等)原样保留。典型的 XML 配置如下:

<bean id="dmnEngineConfiguration" class="org.flowable.dmn.spring.SpringDmnEngineConfiguration"> <!-- 数据源、事务管理器、databaseSchemaUpdate 等常规配置 --> </bean> <bean id="dmnEngine" class="org.flowable.dmn.spring.DmnEngineFactoryBean"> <property name="dmnEngineConfiguration" ref="dmnEngineConfiguration" /> </bean>

注意:dmnEngineConfigurationBean 的 class 必须替换为org.flowable.dmn.spring.SpringDmnEngineConfiguration。从源码看,SpringDmnEngineConfiguration(见 SpringDmnEngineConfiguration.java)继承自DmnEngineConfiguration,并在构造函数中默认完成三件关键工作:

  1. 事务外部托管:构造时直接设置this.transactionsExternallyManaged = true,让引擎的事务边界交由 Spring 的PlatformTransactionManager管理;
  2. 注册三种内置部署策略:默认加入DefaultAutoDeploymentStrategySingleResourceAutoDeploymentStrategyResourceParentFolderAutoDeploymentStrategy
  3. 事务拦截器createTransactionInterceptor()要求必须提供transactionManager,否则抛出FlowableException("transactionManager is required property for SpringDmnEngineConfiguration, ...")

DmnEngineFactoryBean.getObject()中还有一处容易被忽略的细节:如果配置对象是SpringDmnEngineConfiguration且已注入transactionManager,工厂方法会强制设置setTransactionsExternallyManaged(true)(见configureExternallyManagedTransactions())。同时,若配置对象尚未持有 Bean 映射,工厂会用SpringBeanFactoryProxyMap代理整个ApplicationContext,这意味着 DMN 表达式中的 Bean 可以直接按名字解析到 Spring 容器中的实例。

在基于 Java Config 的工程中,配置方式完全等价。仓库测试 DmnSpringJunitJupiterTest.java 给出了一个可直接套用的写法:用@Bean声明SpringDmnEngineConfiguration(注入DataSourcePlatformTransactionManager,设置databaseSchemaUpdate("true")),再用@Bean返回DmnEngineFactoryBean实例:

@Bean public SpringDmnEngineConfiguration dmnEngineConfiguration(DataSource dataSource, PlatformTransactionManager transactionManager) { SpringDmnEngineConfiguration configuration = new SpringDmnEngineConfiguration(); configuration.setDataSource(dataSource); configuration.setTransactionManager(transactionManager); configuration.setDatabaseSchemaUpdate("true"); return configuration; } @Bean public DmnEngineFactoryBean dmnEngine(SpringDmnEngineConfiguration dmnEngineConfiguration) { DmnEngineFactoryBean factoryBean = new DmnEngineFactoryBean(); factoryBean.setDmnEngineConfiguration(dmnEngineConfiguration); return factoryBean; }

此外,SpringDmnEngineConfiguration.setDataSource()对数据源做了透明包装:非TransactionAwareDataSourceProxy类型的数据源会被自动包裹成事务感知代理,从而保证引擎获取的连接能够正确参与 Spring 事务。

自动资源部署:deploymentResources 与去重过滤

Spring 集成提供了一项专门针对资源部署的特性。在SpringDmnEngineConfiguration上设置deploymentResources后,引擎创建完成时会扫描并部署所有匹配的资源:

<bean id="dmnEngineConfiguration" class="org.flowable.dmn.spring.SpringDmnEngineConfiguration"> ... <property name="deploymentResources" value="classpath*:/org/flowable/spring/test/autodeployment/autodeploy/decision*.dmn" /> </bean> <bean id="dmnEngine" class="org.flowable.dmn.spring.DmnEngineFactoryBean"> <property name="dmnEngineConfiguration" ref="dmnEngineConfiguration" /> </bean>

这里的classpath*:前缀会扫描整个 classpath 下的匹配资源。部署过程内置了去重过滤(duplicate filtering):只有当资源实际发生变化时,才会向 Flowable DMN 数据库发起新的部署。这一点对测试等频繁重启 Spring 容器的场景非常有价值——每次重启不会产生重复部署和多余的 DMN 定义新版本。

从源码看,自动部署的触发点在SpringDmnEngineConfiguration.start():它遍历enginesBuild中已构建的引擎,对每个引擎调用autoDeployResources(),后者按deploymentMode解析出对应的AutoDeploymentStrategy,并调用strategy.deployResources(deploymentName, deploymentResources, dmnEngine)。三个策略的公共逻辑位于 AbstractDmnAutoDeploymentStrategy.java:把每个Resource以文件名为资源名通过addInputStream塞入DmnDeploymentBuilder。部署失败时默认只记录 WARN 日志(当异常根因是唯一约束冲突,例如多节点同时启动部署同一批定义时,可以安全忽略),也可以通过CommonAutoDeploymentProperties配置为抛异常。

实现细节上还有两点值得注意:

  • 部署命名deploymentName默认值为SpringAutoDeployment,可以通过setDeploymentName()自定义;
  • 分布式锁:抽象策略通过engine.getDmnEngineConfiguration().getLockManager(determineLockName(deploymentNameHint))获取LockManager,为多实例并发部署提供锁保护。

deploymentMode:三种部署分组策略

默认情况下,上述配置会把所有匹配的资源合并为一个部署,去重过滤作用于整个部署。这在大部分场景下没问题,但存在一个隐患:如果一组资源中只有一个 DMN 定义发生了变化,整个部署仍会被视为“新部署”,从而让该部署内的所有 DMN 定义都生成新版本。

为了精细控制部署的粒度,SpringDmnEngineConfiguration提供了deploymentMode属性,用于定义“如何从匹配资源集合中划分部署”。内置三种取值(分别对应DEPLOYMENT_MODE常量,可从 autodeployment 目录下三个策略类确认):

deploymentMode策略实现类行为
defaultDefaultAutoDeploymentStrategy.java将所有资源归入单个部署,对该部署整体做去重过滤。不指定deploymentMode时即为该值
single-resourceSingleResourceAutoDeploymentStrategy.java每个资源单独创建部署,逐个做去重过滤,并以资源文件名作为部署名。每个 DMN 定义独立演进版本,只有真正变化的定义才会产生新版本
resource-parent-folderResourceParentFolderAutoDeploymentStrategy.java共享同一父目录的资源分组创建部署,部署名形如SpringAutoDeployment.父目录名;若无法确定父目录则回退到资源名。适合“大多数资源独立部署、少数需要分组”的场景

single-resource为例,XML 配置如下:

<bean id="dmnEngineConfiguration" class="org.flowable.dmn.spring.SpringDmnEngineConfiguration"> ... <property name="deploymentResources" value="classpath*:/flowable/*.dmn" /> <property name="deploymentMode" value="single-resource" /> </bean>

需要自定义分组行为时,可以继承SpringDmnEngineConfiguration并重写getAutoDeploymentStrategy(String deploymentMode)方法——该方法的职责正是“根据 deploymentMode 的值解析出对应的部署策略”。源码中的默认实现会遍历deploymentStrategies集合并交给首个handlesMode(mode)返回 true 的策略处理,匹配不到时回退到DefaultAutoDeploymentStrategy(该方法约定永不返回 null,见 SpringDmnEngineConfiguration.java 中的注释)。因此你也可以通过setDeploymentStrategies()注入自定义策略,实现完全可控的部署划分。

单元测试:FlowableDmnSpringExtension 与 @DmnDeployment

Spring 集成保留了 Flowable 标准的测试设施(测试基线与 DMN API 章节 一致),决策可以通过 JUnit Jupiter 快速测试。文档给出的典型写法如下:

@ExtendWith(FlowableDmnSpringExtension.class) @SpringJUnitConfig(DmnSpringJunitJupiterTest.TestConfiguration.class) public class SpringJunit4Test { @Autowired private DmnEngine dmnEngine; @Autowired private DmnRuleService ruleService; @Test @DmnDeploymentAnnotation public void simpleDecisionTest() { Map<String, Object> executionResult = ruleService.createExecuteDecisionBuilder() .decisionKey("extensionUsage") .variable("inputVariable1", 2) .variable("inputVariable2", "test2") .executeWithSingleResult(); Assertions.assertThat(executionResult).containsEntry("output1", "test1"); } }

这套写法对应到仓库中的实际类为:扩展类FlowableDmnSpringExtension(位于 impl/test/FlowableDmnSpringExtension.java,委托给InternalFlowableDmnSpringExtension完成引擎与部署生命周期管理)、注解@DmnDeployment(来自org.flowable.dmn.engine.test包,用于为测试方法自动部署决策资源),断言使用 AssertJ 的assertThat

仓库的真实测试 DmnSpringJunitJupiterTest.java 在此基础上给出了更完整的落地示范:

  • 同时注册FlowableDmnSpringExtension与 Spring 的SpringExtension,并通过@ContextConfiguration(classes = TestConfiguration.class)加载测试配置;
  • 测试方法参数支持注入FlowableDmnTestHelper@DmnDeploymentId String deploymentId以及扩展提供的DmnEngine,测试断言中验证了flowableTestHelper持有的部署 ID、Spring 注入的引擎与扩展注入的引擎是同一个实例;
  • 测试配置类声明了 H2 内存数据源(HikariCP 连接池)、DataSourceTransactionManagerSpringDmnEngineConfiguration(设置databaseSchemaUpdate("true")SpringIdmEngineConfigurator)以及DmnEngineFactoryBean,并将DmnRepositoryServiceDmnDecisionServiceDmnHistoryServiceDmnManagementService逐一暴露为 Bean。

与文档示例略有差异的是:新版测试直接注入了DmnDecisionService(即文档中的DmnRuleService,后者是决策服务接口的历史别名),并让ruleService.createExecuteDecisionBuilder().decisionKey("extensionUsage").variable("input1", "testString").executeWithSingleResult()的返回结果命中containsEntry("output1", "test1"),验证了"输入驱动、输出命中"的完整决策执行闭环。

小结

Flowable DMN 的 Spring 集成可以概括为一条清晰的落地路径:用SpringDmnEngineConfiguration替代标准配置以启用事务外部托管与自动部署能力,通过DmnEngineFactoryBean把引擎注册为单例 Bean,按资源变更粒度从default/single-resource/resource-parent-folder三种deploymentMode中选择合适的部署策略,最后借助FlowableDmnSpringExtension@DmnDeployment在 Spring 上下文中完成决策的自动化测试。无论是 XML 还是 Java Config,这套机制都保持一致的行为语义,可直接套用于生产与测试环境。

【免费下载链接】flowable-engineA compact and highly efficient workflow and Business Process Management (BPM) platform for developers, system admins and business users.项目地址: https://gitcode.com/GitHub_Trending/fl/flowable-engine

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询