flowable部署流程
目录
- 前言
- 一、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部署流程相关推荐
- 第5篇:Flowable快速工作流脚手架Jsite_请假实战_部署流程和发起流程
接上一篇:第4篇:Flowable快速工作流脚手架Jsite_启动项目 https://blog.csdn.net/weixin_40816738/article/details/103388465 ...
- flowable工作流 流程变量_信也科技工作流平台的技术实践
1 背景 随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下: 目前OA流程引擎无法满足企业特定业务流程需求,且移动端体验差,定制化困难,使用门槛高,影响简单流程 ...
- 二次开发:flowable审批流程实践与创建流程源码分析
二次开发:flowable审批流程实践与创建流程源码分析 上一篇已经描述了基于开源项目https://doc.iocoder.cn/的flowable的快速开发,创建了一个租户,创建了用户和相应的岗位 ...
- Twitter的应急预案、部署流程
2019独角兽企业重金招聘Python工程师标准>>> <空中之城>事件 在构建Twitter的架构和系统时,我们是以周为单位来确定那些系统的性能的,我们能清楚地知道每个 ...
- activiti自己定义流程之Spring整合activiti-modeler5.16实例(四):部署流程定义
注:(1)环境搭建:activiti自己定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自己定义流程之Spr ...
- Ironic 裸金属实例的部署流程
目录 文章目录 目录 逻辑架构 部署架构 前提条件 部署流程 iSCSI Deploy UML PXE Deploy Driver Direct Deploy UML IPA Deploy Drive ...
- flowable工作流 流程变量_Activiti工作流的应用示例
1:工作流的概念 工作流(Workflow),就是"业务过程的部分或整体在计算机应用环境下的自动化",它主要解决的是"使在多个参与者之间按照某种预定义的规则传递文档.信息 ...
- Rails 应用使用 Capistrano2 部署流程
Capistrano 2 首次部署流程 修改 config/deploy.rb 和 config/deploy/production.rb bundle exec cap production dep ...
- activiti自定义流程之Spring整合activiti-modeler5.16实例(四):部署流程定义
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自定义流程之Sprin ...
最新文章
- 通过RS232发送和接收短信(二)
- C# WinForm 软件注册的实现
- 偶然发现一个大佬写的 React 脚手架,叫Moderate, 用起来很方便
- 算法移植优化(六)tensorflow模型移植推理优化
- 三星w2014android,三星W2014评测:机身细节及内部设计
- Android BLE(3) ---FastBle解析
- s8050三极管经典电路_电子电路系统的基本概念有哪些?
- \045在字符串中输出为%
- Futter基础第20篇: 实现轮播图 flutter_swiper
- 清华EMBA课程系列思考之十三(2) -- 管理心理学
- 使用三边定位算法进行室内定位
- 键盘表和ASCII码表
- 十大简单易用的免费在线HTML编辑器
- c语言total用法,C语言 这个表达式怎么理解 新手请大神详述total += isalnum(ch[i])!=0;...
- OSChina 周五乱弹 —— 有一个朝代红薯不能去
- 运维必看!阵列硬盘掉线的恢复过程
- Windows XP SP3安装教程(图)
- 共享经济思考:标准化与个性化如何融合
- expected an indented block报错的原因
- 异常:org.apache.ibatis.binding.BindingException: Mapper method 'xyz.mytch.home.dao.HomeDao.findConTota
热门文章
- 知识付费行业现状及典型模式分析
- linux tar 增量备份,tar高级教程:增量备份、定时备份、网络备份
- 百度 AI 商业化表面的风光与背后的艰难,正是全员变身「工程派」的开始
- 什么是spring,它能够做什么?
- kotlin - 线程 Thread
- python打开的文件应该放在哪里-python放在哪里
- 史上最全的iOS各种设备信息获取总结(iPhone 12已更新)
- EOJ3298. 排队买夜宵 (using of stack<...>)
- 博格测试机软件光强介绍,JF-II型LED光电参数测试仪专测光强
- C#连接数据库的登录界面