工作流如何集成事务
Activit整体上采用命令模式进行代码功能解耦。将流程引擎的大部分涉及到客户端的需求让外部以具体命令实现类的方式实现。如节点提交, 最终业务是执行CompleteTaskCmd.class
的execute
方法
public void complete(String taskId, Map<String, Object> variables) {
this.commandExecutor.execute(new CompleteTaskCmd(taskId, variables));
}
Activiti需要搭配对应的拦截器责任链, 通过将创建的事务拦截器添加到责任链中, 实现使后续命令运行在事务环境中.
事务拦截器是否提供取决于ProcessEngineConfigurationImpl.class
的子类对方法createTransactionInterceptor
的实现。
工作流执行其子类SpringProcessEngineConfigurationImpl.class
创建拦截器对象添加到责任链中.
activiti拦截器链
命令拦截器链条由几大块的拦截器实现组成:
默认的拦截器有三个:
- 日志拦截器:
LogInterceptor
- 事务拦截器:
SpringTransactionInterceptor
- CommandContext拦截器:
CommandContextInterceptor
,主要职责是在有必要的时候创建CommandContext对象,并在使用完成后关闭该上下文。
执行顺序 :
LogInterceptor ===> SpringTransactionInterceptor ===> CommandContextInterceptor
初始化流程引擎的时候, 会执行init()进行初始化
// org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl # buildProcessEngine()
public ProcessEngine buildProcessEngine() {
init();
ProcessEngineImpl processEngine = new ProcessEngineImpl(this);
return processEngine;
}
其中initCommanExecutors()
方法中有initCommandInterceptors
方法是对所有拦截器的初始化。
// ProcessEngineConfigurationImpl
protected void initCommandInterceptors() {
if (this.commandInterceptors == null) {
this.commandInterceptors = new ArrayList();
// 添加自定义拦截器
if (this.customPreCommandInterceptors != null) {
this.commandInterceptors.addAll(this.customPreCommandInterceptors);
}
// 添加默认拦截器
this.commandInterceptors.addAll(this.getDefaultCommandInterceptors());
if (this.customPostCommandInterceptors != null) {
this.commandInterceptors.addAll(this.customPostCommandInterceptors);
}
// 命令执行拦截器
this.commandInterceptors.add(this.commandInvoker);
}
}
如何调用第一个拦截器LogInterceptor
拦截器抽象类AbstractCommandInterceptor
提供next属性, 保存下一个拦截器的对象的引用.
ComandExecutor
类用来统一执行所有的命令。在initCommandInterceptors初始化拦截器执行完之后,执行方法initCommandExecutor, 初始化CommandExecutor
// ProcessEngineConfigurationImpl
public void initCommandExecutor() {
if (commandExecutor == null) {
CommandInterceptor first = initInterceptorChain(commandInterceptors);
this.commandExecutor = new CommandExecutorImpl(this.getDefaultCommandConfig(), first);
}
}
其中initInterceptorChain方法设置拦截器链,并设置第一个拦截器
// ProcessEngineConfigurationImpl
public CommandInterceptor initInterceptorChain(List<CommandInterceptor> chain) {
for (int i = 0; i < chain.size() - 1; i++) {
chain.get(i).setNext(chain.get(i + 1));
}
return chain.get(0);
}
- 设置事务的传播属性:
在执行第一个拦截器时, 会传入CommandConfig
参数, 其中保存了事务的传播属性
// this.getDefaultCommandConfig()获取默认参数
this.commandExecutor = new CommandExecutorImpl(this.getDefaultCommandConfig(), first);
CommandConfig
有两个属性, 其构造方法中为propagation设置了默认值为REQUIRED
boolean contextReusePossible; // 表示命令上下文是否可重用 默认值为true
TransactionPropagation propagation; // 事务传播属性 默认值为 REQUIRED
// CommandConfig.class # CommandConfig()
public CommandConfig() {
this.contextReusePossible = true;
this.propagation = TransactionPropagation.REQUIRED;
}
创建SpringTransactionInterceptor
步骤
在JpaProcessEngineAutoConfiguration.class
的内部类DataSourceProcessEngineConfiguration.class
中, 会创建transactionManager和springProcessEngineConfiguration两个bean
- 创建
transactionManager
Bean为DataSourceProcessEngineConfiguration
实例 - 创建
springProcessEngineConfiguration
Bean时, 执行this.baseSpringProcessEngineConfiguration()
方法,
@Bean
@ConditionalOnMissingBean
public PlatformTransactionManager transactionManager() {
return new DataSourceProcessEngineConfiguration(emf);
}
@Bean
@ConditionalOnMissingBean
public SpringProcessEngineConfiguration springProcessEngineConfiguration(){
SpringProcessEngineConfiguration config = this.baseSpringProcessEngineConfiguration(dataSource, transactionManager, springAsyncExecutor);
config.setTransactionManager(transactionManager);
...
return config;
}
通过调用其父类的父类的processEngineConfigurationBean()
方法, 创建SpringProcessEngineConfiguration
实例后, 调用实例的setTransactionManager()
方法. 将DataSourceProcessEngineConfiguration
对象赋值给processEngine.
processEngine获得事务管理器DataSourceProcessEngineConfiguration
而后, 在初始化工作流的流程引擎processEngine时, 获取事务拦截器, 调用其子类SpringProcessEngineConfiguration.class
的createTransactionInterceptor()
, 返回SpringTransactionInterceptor
对象, 在判空之后添加到责任链中
// ProcessEngineConfigurationImpl.class
protected Collection<? extends CommandInterceptor> getDefaultCommandInterceptors() {
// 创建拦截器链
List<CommandInterceptor> interceptors = new ArrayList();
interceptors.add(new LogInterceptor());
// 调用子类方法, 创建事务拦截器 SpringTransactionInterceptor
CommandInterceptor transactionInterceptor = this.createTransactionInterceptor();
if (transactionInterceptor != null) {
// 将事务拦截器添加到责任链中
interceptors.add(transactionInterceptor);
}
// 添加默认命令拦截器, 主要职责是在有必要的时候创建CommandContext对象,并在使用完成后关闭该上下文。
interceptors.add(new CommandContextInterceptor(this.commandContextFactory, this));
return interceptors;
}
// 抽象方法, 取决于子类对此方法的实现
protected abstract CommandInterceptor createTransactionInterceptor();
由此可见, activiti实际还是托管于spring来实现事务功能
关闭activiti事务管理
activiti中存在一个命令拦截器链条,事务拦截器是其中一部分, 主要职责是使后续命令运行在事务环境下.
ProcessEngineConfigurationImpl.class
的getDefaultCommandInterceptors()
方法中, 创建事务拦截器, 经过判空判断后添加到拦截器链中.
使事务失效方法:
-
注释掉添加拦截器到链中的代码, 使事务失效
if (transactionInterceptor != null) { // interceptors.add(transactionInterceptor); }
-
SpringProcessEngineConfiguration.class # createTransactionInterceptor()
创建事务拦截器的方法返回null
工作流中事务执行逻辑
activiti通过transactionTemplate
, 使用spring的编程式事务来管理自身事务
事务拦截器SpringTransactionInterceptor.class
实现CommandInterceptor.class
接口, 拦截到的每个动作执行该类的execute方法.
通过 TransactionTemplate
将动作置于spring事务范围内
此方法有两个参数: 参数 config中包含属性propagation 表示事务传播行为 支持三种 NOT_SUPPORTED、REQUIRED、REQUIRES_NEW
参数 command 是命令接口, 所有的具体命令都需要实现该类,最终业务就是执行该类的execute方法。
// SpringTransactionInterceptor.class # execute()
public <T> T execute(final CommandConfig config, final Command<T> command) {
TransactionTemplate transactionTemplate = new TransactionTemplate(this.transactionManager);
// 为transactionTemplate设置事务管理器DataSourceProcessEngineConfiguration
transactionTemplate.setPropagationBehavior(this.getPropagation(config));
// 执行下一个拦截器
T result = transactionTemplate.execute((status) -> {return next.execute(config, command);});
return result;
}
SpringTransactionInterceptor.class
有两个属性
transactionManager: 事务管理器 类型PlatformTransactionManager
实例 DataSourceProcessEngineConfiguration
next: 责任链的下一个拦截器 类型CommandInterceptor
实例 CommandContextInterceptor
监听器初始化与执行逻辑
- 初始化监听器
对于全局监听器
初始化ProcessEngine时, ProcessEngineConfigurationImpl.class
初始化事件选择器, 遍历eventListeners和typedEventListeners对象, 将每个监听器添加到eventDispatcher对象中
- 执行监听器
添加"beforeComplete"监听器, 完成任务 调用activiti TaskServiceImpl.complete()
方法:
具体执行逻辑在CompleteTaskCmd.class类的execute()方法, 首先task.fireEvent(“beforeComplete”), 启动绑定了"beforeComplete"事件的监听器
// CompleteTaskCmd.class # execute()
protected Void execute(CommandContext commandContext, TaskEntity task) {
task.fireEvent("beforeComplete");
...
task.complete(this.variables, this.localScope);
return null;
}
fireEvent()方法在任务节点定义中获取对应事件的监听器, 遍历执行监听器逻辑
// TaskEntity.class # fireEvent()
public void fireEvent(String taskEventName) {
List<TaskListener> taskEventListeners = this.getTaskDefinition().getTaskListener(taskEventName);
...
// 创建TaskListenerInvocation, 执行此监听器逻辑
Context.getProcessEngineConfiguration().getDelegateInterceptor().handleInvocation(new TaskListenerInvocation(taskListener, this));
}
handleInvocation()方法执行传入的TaskListenerInvocation对象的invoke方法,
// TaskListenerInvocation.class # invoke()
protected void invoke() throws Exception {
this.executionListenerInstance.notify(this.delegateTask);
}
每个任务监听器都要实现notify()方法, 调用实际监听器的notify()方法, 执行逻辑代码.
activiti如何操作自身数据库
以完成某一节点任务, 执行activiti taskServiceImpl.complete()
方法为例
完成节点任务需要删除BPM_ACT_RUN_TASK
表中正在操作的词条待办任务, 插入下一节点任务到待办中, 故会执行Task持久化类TaskEntityManager.deleteTask()
方法
删除待办数据需要首先删除此条待办在执行人表中对应数据, 会调用执行人表持久化类getIdentityLinkEntityManager.deleteIdentityLinksByTaskId(taskId)
方法
// IdentityLinkEntityManager.class # deleteIdentityLink
public void deleteIdentityLink(IdentityLinkEntity identityLink, boolean cascadeHistory){
this.getDbSqlSession().delete(identityLink);
}
activiti 通过sqlSession的方式进行数据持久化, 使用sqlSession的实现类DefaultSqlSession存储在DbSqlSession对象中
public class DbSqlSession implements Session{
protected SqlSession sqlSession;
}
delete方法则是将每一个要删除的对象创建为一个DbSqlSession
的内部类CheckedDeleteOperation
去保存删除的动作, 但此时还并未执行.
public void delete(PersistentObject persistentObject) {
...
this.deleteOperations.add(new DbSqlSession.CheckedDeleteOperation(persistentObject));
...
}
而实际的删除动作在CheckedDeleteOperation.class
的execute()
方法中通过sqlSession删除
//DbSqlSession.CheckedDeleteOperation.class # execute()
public void execute(){
sqlSession.delete(deleteStatement, persistentObject);
}
execute()动作的调用是在执行DbSqlSession的刷新动作时, 调用flush()方法, 统一执行对activiti系统数据库的添加修改删除操作
// DbSqlSession.class
@Override
public void flush(){
...
flushInserts();
flushUpdates(updatedObjects);
flushDeletes(removedOperations);
}
fulsh()方法的执行时机则是
在事务拦截器后还有一层进行初始化命令上下文的拦截器, 在activiti的逻辑及监听器逻辑执行完成后在finally代码段中关闭上下文环境, 执行context.close();
在CommandContextInterceptor.close()
的方法中, 若此时无异常发生, 则执行flush刷新, 并在finally中, 没有异常时执行transactionContext.commit()
// CommandContextInterceptor.class
public <T> T execute(CommandConfig config, Command<T> command){
}finally {
context.close();
}
// CommandContext.class
public void close(){
if (exception == null) {
flushSessions();
}
...
} finally {
if (exception == null) {
transactionContext.commit();
}
if (exception != null) {
...
transactionContext.rollback();
}
}finally{
closeSessions();
}
}
在最后的finally会遍历CommandContext中的session依次关闭.
即在执行activiti提供给外部的接口 如RuntimeService.startProcessInstanceById()
TaskService.complete()
时, 因为监听器的具体逻辑是在接口内部调用执行, 只有在监听器执行完毕后进入finally中才执行flush进行持久化, 若监听器产生异常, activit并未持久化, 不必回滚.
transactionContext的实例SpringTransactionContext.class
, commit()方法为空, rollback()方法设置rollbackonly=true;
// SpringTransactionContext.class
public void commit() {
// Do nothing, transaction is managed by spring
}
public void rollback() {
transactionManager.getTransaction(null).setRollbackOnly();
}
transactionContext的对象SpringTransactionContext.class
的commit并未执行实际的动作, 将具体的commit和rollback托管给DataSourceProcessEngineConfiguration
去执行
SqlSession的获取及其初始化
SqlSession作为类DbSqlSession的一个属性存储在DbSqlSession中, 在DbSqlSession的构造方法中提供了初始化sqlSession的方法. 在创建DbSqlSession时, 会同时创建sqlSession
而DbSqlSession可以通过Context的静态方法获取, 首先获取CommandContext对象, 再获取session.
Context用来保存activiti的全局变量或运行周期很长的变量得类, 由多个静态ThreadLocal变量组成
Context.getCommandContext().getSession(DbSqlSession.class)
CommandContext的初始化是在命令上下文拦截器的方法CommandContextInterceptor.execute()
中, 获取默认的CommandContext()存储到ThreadLocal中
// CommandContextInterceptor.class
public <T> T execute(CommandConfig config, Command<T> command){
context = this.commandContextFactory.createCommandContext(command);
Context.setCommandContext(context);
}
CommandContext.getSession()方法中, 在获取DbSqlSession的工厂类DbSqlSessionFactory后openSession()获取session
sessionFactories中存储了工作流各个session的工厂类, 在系统启动初始化processEngine时创建
// CommandContext.class
public <T> T getSession(Class<T> sessionClass) {
SessionFactory sessionFactory = sessionFactories.get(sessionClass);
// openSesion 获取Session实例
session = sessionFactory.openSession();
}
// DbSqlSessionFactory.class
public Session openSession() {
return new DbSqlSession(this);
}
创建对象时, 执行DbSqlSession的构造方法, 在初始化DbSqlSession时为其属性sqlSession赋值
public DbSqlSession(DbSqlSessionFactory dbSqlSessionFactory) {
this.dbSqlSessionFactory = dbSqlSessionFactory;
this.sqlSession = dbSqlSessionFactory.getSqlSessionFactory().openSession();
}
其中SqlSessionFactory的实例是DefaultSqlSessionFactory.class
位于mybatis包中
而SqlSessionFactory的初始化是在系统启动, 初始化ProcessEngine时, 在ProcessEngineConfigurationImpl
的initSqlSessionFactory()
方法中创建SqlSessionFactory对象, 在initSessionFactories()
方法中初始化DbSqlSessionFactory并将DefaultSqlSessionFactory赋值给sqlSessionFactory属性.
CommandContext.getSession()方法中使用到的sessionFactories属性也是在这里初始化, 通过addSessionFactory()方法将每个Session的工厂类存储到sessionFactories中.
// ProcessEngineConfigurationImpl.class
protected void initSessionFactories() {
sessionFactories = new HashMap<Class<?>, SessionFactory>();
if (dbSqlSessionFactory == null) {
dbSqlSessionFactory = new DbSqlSessionFactory();
}
dbSqlSessionFactory.setSqlSessionFactory(sqlSessionFactory);
...
// 将dbSqlSessionFactory添加到sessionFactories中
addSessionFactory(dbSqlSessionFactory);
...
}