前言
分析一下 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));
}
//其他拦截器,BpmnOverrideContextInterceptor
List<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、示例
@Test
public void createDeployment() {
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("holiday-request.bpmn20.xml")
.deploy();
System.out.println(deployment.getId());
}
2、createDeployment()
(1)createDeployment()
@Override
public DeploymentBuilder createDeployment() {
return commandExecutor.execute(new Command<DeploymentBuilder>() {
//执行完拦截器链,回调当前方法,返回 DeploymentBuilderImpl 对象
@Override
public DeploymentBuilder execute(CommandContext commandContext) {
return new DeploymentBuilderImpl(RepositoryServiceImpl.this);
}
});
}
(2)执行拦截器链
@Override
public <T> T execute(Command<T> command) {
return execute(defaultConfig, command);
}
@Override
public <T> T execute(CommandConfig config, Command<T> command) {
return first.execute(config, command, this);
}
(3)DeploymentBuilderImpl
public DeploymentBuilderImpl(RepositoryServiceImpl repositoryService) {
//RepositoryServiceImpl
this.repositoryService = repositoryService;
//DeploymentEntityImpl
this.deployment = CommandContextUtil.getProcessEngineConfiguration().getDeploymentEntityManager().create();
//ResourceEntityManagerImpl
this.resourceEntityManager = CommandContextUtil.getProcessEngineConfiguration().getResourceEntityManager();
}
3、addClasspathResource(“holiday-request.bpmn20.xml”)
用于解析文件流
(1)addClasspathResource()
@Override
public 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()
@Override
public DeploymentBuilder addInputStream(String resourceName, InputStream inputStream) {
if (inputStream == null) {
throw new FlowableIllegalArgumentException("inputStream for resource '" + resourceName + "' is null");
}
//读取文件
byte[] bytes = IoUtil.readInputStream(inputStream, resourceName);
//创建 ResourceEntityImpl
ResourceEntity resource = resourceEntityManager.create();
resource.setName(resourceName);
resource.setBytes(bytes);
//将resource 放到 DeploymentEntityImpl 中
deployment.addResource(resource);
return this;
}
4、deploy()
执行部署
(1)deploy()
DeploymentBuilderImpl.java
@Override
public Deployment deploy() {
return repositoryService.deploy(this);
}
RepositoryServiceImpl.java
public Deployment deploy(DeploymentBuilderImpl deploymentBuilder) {
return commandExecutor.execute(new DeployCmd<Deployment>(deploymentBuilder));
}
在拦截器链的尽头,会回调 DeployCmd 的 execute() 方法
(2)DeployCmd.execute()
@Override
public 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()) {
//查询出来重复的 Deployment
List<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 deployments
deployment.setParentDeploymentId(deployment.getId());
}
FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher();
if (eventDispatcher != null && eventDispatcher.isEnabled()) {
//发布事件 ENTITY_CREATED
eventDispatcher.dispatchEvent(FlowableEventBuilder.createEntityEvent(FlowableEngineEventType.ENTITY_CREATED, deployment),
processEngineConfiguration.getEngineCfgKey());
}
// Deployment settings
Map<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)保存到数据库
实际上是先缓存起来
@Override
public void insert(DeploymentEntity deployment) {
//保存 deployment
insert(deployment, false);
//保存 resource
for (EngineResource resource : deployment.getResources().values()) {
resource.setDeploymentId(deployment.getId());
getResourceEntityManager().insert((ResourceEntity) resource);
}
}
保存的逻辑,是将数据对象先存储到 SqlSession 的缓存中
@Override
public void insert(EntityImpl entity, boolean fireCreateEvent) {
getDataManager().insert(entity);
if (fireCreateEvent) {
fireEntityInsertedEvent(entity);
}
}
@Override
public void insert(EntityImpl entity) {
getDbSqlSession().insert(entity, getIdGenerator());
}
public void insert(Entity entity, IdGenerator idGenerator) {
if (entity.getId() == null) {
//生成id
String 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 changed
entity.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()
@Override
public void flush() {
determineUpdatedObjects(); // Needs to be done before the removeUnnecessaryOperations, as removeUnnecessaryOperations will remove stuff from the cache
removeUnnecessaryOperations();
//打印日志
if (LOGGER.isDebugEnabled()) {
debugFlush();
}
//Insert
flushInserts();
//Update
flushUpdates();
//Delete
flushDeletes();
}
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-1290
if (entity instanceof HasRevision) {
incrementRevision(entity);
}
}
8、 insert()
到了 mybatis 的流程,执行插入数据库操作
@Override
public int insert(String statement, Object parameter) {
return update(statement, parameter);
}
@Override
public 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 流程资源表