目录

  • 前言
  • 一、CommandExecutor
  • 二、部署流程
  • 三、写入数据库

前言

分析一下 flowable 的部署流程

一、CommandExecutor

在流程执行的过程中,都会经过 CommandExecutor 执行,所以先分析一下CommandExecutor

1、CommandExecutor 的初始化

在流程引擎初始化过程中

CommandExecutor -> init() -> initCommandExecutors() -> initCommandInterceptors() 和 initCommandExecutor()

2、initCommandInterceptors()

public void initCommandInterceptors() {if (commandInterceptors == null) {commandInterceptors = new ArrayList<>();if (customPreCommandInterceptors != null) {commandInterceptors.addAll(customPreCommandInterceptors);}//默认拦截器            commandInterceptors.addAll(getDefaultCommandInterceptors());if (customPostCommandInterceptors != null) {commandInterceptors.addAll(customPostCommandInterceptors);}//CommandInvoker 拦截器commandInterceptors.add(commandInvoker);}}
public Collection<? extends CommandInterceptor> getDefaultCommandInterceptors() {if (defaultCommandInterceptors == null) {List<CommandInterceptor> interceptors = new ArrayList<>();//日志拦截器interceptors.add(new LogInterceptor());//cockroachdb 重试拦截器if (DATABASE_TYPE_COCKROACHDB.equals(databaseType)) {interceptors.add(new CrDbRetryInterceptor());}//事务拦截器CommandInterceptor transactionInterceptor = createTransactionInterceptor();if (transactionInterceptor != null) {interceptors.add(transactionInterceptor);}if (commandContextFactory != null) {String engineCfgKey = getEngineCfgKey();//Command 上下文拦截器CommandContextInterceptor commandContextInterceptor = new CommandContextInterceptor(commandContextFactory, classLoader, useClassForNameClassLoading, clock, objectMapper);engineConfigurations.put(engineCfgKey, this);commandContextInterceptor.setEngineCfgKey(engineCfgKey);commandContextInterceptor.setEngineConfigurations(engineConfigurations);interceptors.add(commandContextInterceptor);}if (transactionContextFactory != null) {//transaction 上下文拦截器interceptors.add(new TransactionContextInterceptor(transactionContextFactory));}//其他拦截器,BpmnOverrideContextInterceptorList<CommandInterceptor> additionalCommandInterceptors = getAdditionalDefaultCommandInterceptors();if (additionalCommandInterceptors != null) {interceptors.addAll(additionalCommandInterceptors);}defaultCommandInterceptors = interceptors;}return defaultCommandInterceptors;}

3、initCommandExecutor()

public void initCommandExecutor() {if (commandExecutor == null) {//初始化了拦截器链CommandInterceptor first = initInterceptorChain(commandInterceptors);//传入拦截器链,创建执行器commandExecutor = new CommandExecutorImpl(getDefaultCommandConfig(), first);}}
public CommandInterceptor initInterceptorChain(List<CommandInterceptor> chain) {if (chain == null || chain.isEmpty()) {throw new FlowableException("invalid command interceptor chain configuration: " + chain);}//设置setNext,构建执行器链for (int i = 0; i < chain.size() - 1; i++) {chain.get(i).setNext(chain.get(i + 1));}return chain.get(0);}

二、部署流程

1、示例

 @Testpublic void createDeployment() {Deployment deployment = repositoryService.createDeployment().addClasspathResource("holiday-request.bpmn20.xml").deploy();System.out.println(deployment.getId());}

2、createDeployment()

(1)createDeployment()

 @Overridepublic DeploymentBuilder createDeployment() {return commandExecutor.execute(new Command<DeploymentBuilder>() {//执行完拦截器链,回调当前方法,返回 DeploymentBuilderImpl 对象@Overridepublic DeploymentBuilder execute(CommandContext commandContext) {return new DeploymentBuilderImpl(RepositoryServiceImpl.this);}});}

(2)执行拦截器链

     @Overridepublic <T> T execute(Command<T> command) {return execute(defaultConfig, command);}@Overridepublic <T> T execute(CommandConfig config, Command<T> command) {return first.execute(config, command, this);}

(3)DeploymentBuilderImpl

 public DeploymentBuilderImpl(RepositoryServiceImpl repositoryService) {//RepositoryServiceImplthis.repositoryService = repositoryService;//DeploymentEntityImplthis.deployment = CommandContextUtil.getProcessEngineConfiguration().getDeploymentEntityManager().create();//ResourceEntityManagerImplthis.resourceEntityManager = CommandContextUtil.getProcessEngineConfiguration().getResourceEntityManager();}

3、addClasspathResource(“holiday-request.bpmn20.xml”)

用于解析文件流

(1)addClasspathResource()

 @Overridepublic DeploymentBuilder addClasspathResource(String resource) {//获取文件流InputStream inputStream = ReflectUtil.getResourceAsStream(resource);if (inputStream == null) {throw new FlowableIllegalArgumentException("resource '" + resource + "' not found");}//处理文件流return addInputStream(resource, inputStream);}

(2)addInputStream()

 @Overridepublic DeploymentBuilder addInputStream(String resourceName, InputStream inputStream) {if (inputStream == null) {throw new FlowableIllegalArgumentException("inputStream for resource '" + resourceName + "' is null");}//读取文件byte[] bytes = IoUtil.readInputStream(inputStream, resourceName);//创建 ResourceEntityImplResourceEntity resource = resourceEntityManager.create();resource.setName(resourceName);resource.setBytes(bytes);//将resource 放到 DeploymentEntityImpl 中deployment.addResource(resource);return this;}

4、deploy()

执行部署

(1)deploy()

 DeploymentBuilderImpl.java@Overridepublic Deployment deploy() {return repositoryService.deploy(this);}
 RepositoryServiceImpl.javapublic Deployment deploy(DeploymentBuilderImpl deploymentBuilder) {return commandExecutor.execute(new DeployCmd<Deployment>(deploymentBuilder));}

在拦截器链的尽头,会回调 DeployCmd 的 execute() 方法

(2)DeployCmd.execute()

     @Overridepublic Deployment execute(CommandContext commandContext) {// Backwards compatibility with v5//flowable5 的逻辑if (deploymentBuilder.getDeploymentProperties() != null&& deploymentBuilder.getDeploymentProperties().containsKey(DeploymentProperties.DEPLOY_AS_FLOWABLE5_PROCESS_DEFINITION)&& deploymentBuilder.getDeploymentProperties().get(DeploymentProperties.DEPLOY_AS_FLOWABLE5_PROCESS_DEFINITION).equals(Boolean.TRUE)) {ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);if (processEngineConfiguration.isFlowable5CompatibilityEnabled() && processEngineConfiguration.getFlowable5CompatibilityHandler() != null) {return deployAsFlowable5ProcessDefinition(commandContext);} else {throw new FlowableException("Can't deploy a v5 deployment with no flowable 5 compatibility enabled or no compatibility handler on the classpath");}}//执行部署return executeDeploy(commandContext);}

(3)executeDeploy()

protected Deployment executeDeploy(CommandContext commandContext) {DeploymentEntity deployment = deploymentBuilder.getDeployment();ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);//设置部署时间deployment.setDeploymentTime(processEngineConfiguration.getClock().getCurrentTime());//如果开启了过滤重复的开关if (deploymentBuilder.isDuplicateFilterEnabled()) {//查询出来重复的 DeploymentList<Deployment> existingDeployments = new ArrayList<>();if (deployment.getTenantId() == null || ProcessEngineConfiguration.NO_TENANT_ID.equals(deployment.getTenantId())) {List<Deployment> deploymentEntities = new DeploymentQueryImpl(processEngineConfiguration.getCommandExecutor()).deploymentName(deployment.getName()).orderByDeploymentTime().desc().listPage(0, 1);if (!deploymentEntities.isEmpty()) {existingDeployments.add(deploymentEntities.get(0));}} else {List<Deployment> deploymentList = processEngineConfiguration.getRepositoryService().createDeploymentQuery().deploymentName(deployment.getName()).deploymentTenantId(deployment.getTenantId()).orderByDeploymentTime().desc().listPage(0, 1);if (!deploymentList.isEmpty()) {existingDeployments.addAll(deploymentList);}}if (!existingDeployments.isEmpty()) {DeploymentEntity existingDeployment = (DeploymentEntity) existingDeployments.get(0);//校验数据库的和当前的是否相同if (!deploymentsDiffer(deployment, existingDeployment)) {return existingDeployment;}}}//新的部署流程deployment.setNew(true);// Save the data//保存到数据库processEngineConfiguration.getDeploymentEntityManager().insert(deployment);if (StringUtils.isEmpty(deployment.getParentDeploymentId())) {// If no parent deployment id is set then set the current ID as the parent// If something was deployed via this command than this deployment would// be a parent deployment to other potential child deploymentsdeployment.setParentDeploymentId(deployment.getId());}FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher();if (eventDispatcher != null && eventDispatcher.isEnabled()) {//发布事件 ENTITY_CREATEDeventDispatcher.dispatchEvent(FlowableEventBuilder.createEntityEvent(FlowableEngineEventType.ENTITY_CREATED, deployment),processEngineConfiguration.getEngineCfgKey());}// Deployment settingsMap<String, Object> deploymentSettings = new HashMap<>();deploymentSettings.put(DeploymentSettings.IS_BPMN20_XSD_VALIDATION_ENABLED, deploymentBuilder.isBpmn20XsdValidationEnabled());deploymentSettings.put(DeploymentSettings.IS_PROCESS_VALIDATION_ENABLED, deploymentBuilder.isProcessValidationEnabled());// Actually deploy//部署,解析bpmn文件等processEngineConfiguration.getDeploymentManager().deploy(deployment, deploymentSettings);if (deploymentBuilder.getProcessDefinitionsActivationDate() != null) {scheduleProcessDefinitionActivation(commandContext, deployment);}if (eventDispatcher != null && eventDispatcher.isEnabled()) {eventDispatcher.dispatchEvent(FlowableEventBuilder.createEntityEvent(FlowableEngineEventType.ENTITY_INITIALIZED, deployment),processEngineConfiguration.getEngineCfgKey());}return deployment;}

(4)保存到数据库

实际上是先缓存起来

     @Overridepublic void insert(DeploymentEntity deployment) {//保存 deploymentinsert(deployment, false);//保存 resourcefor (EngineResource resource : deployment.getResources().values()) {resource.setDeploymentId(deployment.getId());getResourceEntityManager().insert((ResourceEntity) resource);}}

保存的逻辑,是将数据对象先存储到 SqlSession 的缓存中

     @Overridepublic void insert(EntityImpl entity, boolean fireCreateEvent) {getDataManager().insert(entity);if (fireCreateEvent) {fireEntityInsertedEvent(entity);}}
 @Overridepublic void insert(EntityImpl entity) {getDbSqlSession().insert(entity, getIdGenerator());}
public void insert(Entity entity, IdGenerator idGenerator) {if (entity.getId() == null) {//生成idString id = idGenerator.getNextId();if (dbSqlSessionFactory.isUsePrefixId()) {id = entity.getIdPrefix() + id;}entity.setId(id);}Class<? extends Entity> clazz = entity.getClass();if (!insertedObjects.containsKey(clazz)) {insertedObjects.put(clazz, new LinkedHashMap<>()); // order of insert is important, hence LinkedHashMap}//存到 insertedObjects 中insertedObjects.get(clazz).put(entity.getId(), entity);entityCache.put(entity, false); // False -> entity is inserted, so always changedentity.setInserted(true);}

三、写入数据库

上面的流程是将数据存在了缓存中,真正写入数据库的操作是在 CommandContextInterceptor 的finally() 方法中,调用 commandContext.close(),会触发写入数据库的操作

1、finally

     finally {try {if (!contextReused) {commandContext.close();}commandContext.setReused(originalContextReusedState);}

2、 commandContext.close()

 public void close() {...flushSessions();...

3、 flushSessions()

 protected void flushSessions() {for (Session session : sessions.values()) {session.flush();}}

4、 DbSqlSession.flush()

     @Overridepublic void flush() {determineUpdatedObjects(); // Needs to be done before the removeUnnecessaryOperations, as removeUnnecessaryOperations will remove stuff from the cacheremoveUnnecessaryOperations();//打印日志if (LOGGER.isDebugEnabled()) {debugFlush();}//InsertflushInserts();//UpdateflushUpdates();//DeleteflushDeletes();}

5、 flushInserts()

 protected void flushInserts() {//检查缓存要写入数据库的数据if (insertedObjects.size() == 0) {return;}// Handle in entity dependency order//按顺序写入数据库for (Class<? extends Entity> entityClass : dbSqlSessionFactory.getInsertionOrder()) {if (insertedObjects.containsKey(entityClass)) {flushInsertEntities(entityClass, insertedObjects.get(entityClass).values());insertedObjects.remove(entityClass);}}// Next, in case of custom entities or we've screwed up and forgotten some entity//其他自定义的对象写入数据库if (insertedObjects.size() > 0) {for (Class<? extends Entity> entityClass : insertedObjects.keySet()) {flushInsertEntities(entityClass, insertedObjects.get(entityClass).values());}}insertedObjects.clear();}

6、 flushInsertEntities()

protected void flushInsertEntities(Class<? extends Entity> entityClass, Collection<Entity> entitiesToInsert) {if (entitiesToInsert.size() == 1) {//单条写入flushRegularInsert(entitiesToInsert.iterator().next(), entityClass);} else if (Boolean.FALSE.equals(dbSqlSessionFactory.isBulkInsertable(entityClass))) {for (Entity entity : entitiesToInsert) {flushRegularInsert(entity, entityClass);}} else {//批量写入flushBulkInsert(entitiesToInsert, entityClass);}}

7、 flushRegularInsert()

protected void flushRegularInsert(Entity entity, Class<? extends Entity> clazz) {String insertStatement = dbSqlSessionFactory.getInsertStatement(entity);insertStatement = dbSqlSessionFactory.mapStatement(insertStatement);if (insertStatement == null) {throw new FlowableException("no insert statement for " + entity.getClass() + " in the ibatis mapping files");}LOGGER.debug("inserting: {}", entity);// insert 操作sqlSession.insert(insertStatement, entity);// See https://activiti.atlassian.net/browse/ACT-1290if (entity instanceof HasRevision) {incrementRevision(entity);}}

8、 insert()

到了 mybatis 的流程,执行插入数据库操作

  @Overridepublic int insert(String statement, Object parameter) {return update(statement, parameter);}
 @Overridepublic int update(String statement, Object parameter) {try {dirty = true;MappedStatement ms = configuration.getMappedStatement(statement);return executor.update(ms, wrapCollection(parameter));} catch (Exception e) {throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}}

调用flowable自定义的mapper.xml文件执行sql

总结:

在流程部署中,涉及到的几个关键的表:

1、ACT_RE_PROCDEF 流程定义表
2、ACT_RE_DEPLOYMENT 流程部署表
3、ACT_GE_BYTEARRAY 流程资源表

flowable部署流程相关推荐

  1. 第5篇:Flowable快速工作流脚手架Jsite_请假实战_部署流程和发起流程

    接上一篇:第4篇:Flowable快速工作流脚手架Jsite_启动项目 https://blog.csdn.net/weixin_40816738/article/details/103388465 ...

  2. flowable工作流 流程变量_信也科技工作流平台的技术实践

    1 背景 随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下: 目前OA流程引擎无法满足企业特定业务流程需求,且移动端体验差,定制化困难,使用门槛高,影响简单流程 ...

  3. 二次开发:flowable审批流程实践与创建流程源码分析

    二次开发:flowable审批流程实践与创建流程源码分析 上一篇已经描述了基于开源项目https://doc.iocoder.cn/的flowable的快速开发,创建了一个租户,创建了用户和相应的岗位 ...

  4. Twitter的应急预案、部署流程

    2019独角兽企业重金招聘Python工程师标准>>> <空中之城>事件 在构建Twitter的架构和系统时,我们是以周为单位来确定那些系统的性能的,我们能清楚地知道每个 ...

  5. activiti自己定义流程之Spring整合activiti-modeler5.16实例(四):部署流程定义

    注:(1)环境搭建:activiti自己定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建         (2)创建流程模型:activiti自己定义流程之Spr ...

  6. Ironic 裸金属实例的部署流程

    目录 文章目录 目录 逻辑架构 部署架构 前提条件 部署流程 iSCSI Deploy UML PXE Deploy Driver Direct Deploy UML IPA Deploy Drive ...

  7. flowable工作流 流程变量_Activiti工作流的应用示例

    1:工作流的概念 工作流(Workflow),就是"业务过程的部分或整体在计算机应用环境下的自动化",它主要解决的是"使在多个参与者之间按照某种预定义的规则传递文档.信息 ...

  8. Rails 应用使用 Capistrano2 部署流程

    Capistrano 2 首次部署流程 修改 config/deploy.rb 和 config/deploy/production.rb bundle exec cap production dep ...

  9. activiti自定义流程之Spring整合activiti-modeler5.16实例(四):部署流程定义

    注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建         (2)创建流程模型:activiti自定义流程之Sprin ...

最新文章

  1. 通过RS232发送和接收短信(二)
  2. C# WinForm 软件注册的实现
  3. 偶然发现一个大佬写的 React 脚手架,叫Moderate, 用起来很方便
  4. 算法移植优化(六)tensorflow模型移植推理优化
  5. 三星w2014android,三星W2014评测:机身细节及内部设计
  6. Android BLE(3) ---FastBle解析
  7. s8050三极管经典电路_电子电路系统的基本概念有哪些?
  8. \045在字符串中输出为%
  9. Futter基础第20篇: 实现轮播图 flutter_swiper
  10. 清华EMBA课程系列思考之十三(2) -- 管理心理学
  11. 使用三边定位算法进行室内定位
  12. 键盘表和ASCII码表
  13. 十大简单易用的免费在线HTML编辑器
  14. c语言total用法,C语言 这个表达式怎么理解 新手请大神详述total += isalnum(ch[i])!=0;...
  15. OSChina 周五乱弹 —— 有一个朝代红薯不能去
  16. 运维必看!阵列硬盘掉线的恢复过程
  17. Windows XP SP3安装教程(图)
  18. 共享经济思考:标准化与个性化如何融合
  19. expected an indented block报错的原因
  20. 异常:org.apache.ibatis.binding.BindingException: Mapper method 'xyz.mytch.home.dao.HomeDao.findConTota

热门文章

  1. 知识付费行业现状及典型模式分析
  2. linux tar 增量备份,tar高级教程:增量备份、定时备份、网络备份
  3. 百度 AI 商业化表面的风光与背后的艰难,正是全员变身「工程派」的开始
  4. 什么是spring,它能够做什么?
  5. kotlin - 线程 Thread
  6. python打开的文件应该放在哪里-python放在哪里
  7. 史上最全的iOS各种设备信息获取总结(iPhone 12已更新)
  8. EOJ3298. 排队买夜宵 (using of stack<...>)
  9. 博格测试机软件光强介绍,JF-II型LED光电参数测试仪专测光强
  10. C#连接数据库的登录界面