在 Activiti BPMN 中使用非序列化对象
Using Non Serializable objects in Activiti BPMN
我想使用 Activiti BPMN 流程来完成一些数据库更新任务。我的流程如下
开始事件 -> 服务任务 1 -> 服务任务 2 -> 服务任务 3 -> 结束事件
在服务任务 1 的服务实现 class 中:我为 MySQL 数据库创建了一个 java.sql.Connection。我需要将相同的 Connection 对象传递给服务任务 2 和服务任务 3。基本上,这两个 classes 将使用相同的 Connection 对象为数据库执行一些插入操作。
我尝试如下(dbConn 是包含 java.sql.Connection 类型 dbConnection 的 Class)
execution.setVariable("DBConn",dbConn);
但是它给出了一个异常,因为连接对象是不可序列化的。
"org.activiti.engine.ActivitiException: Couldn't serialize value"
那么在进程的服务任务之间传递此类不可序列化变量的最佳方式是什么?或者有什么方法可以在一个地方为多个服务任务定义这样的公共对象,并在服务任务中使用它们(类似于流程的全局变量)
首先,您应该知道,一旦根据 this.
创建了连接实例,就绝对没有办法对其进行序列化。
The reason is that a connection uses a network resource (such as a TCP/IP socket) which uses the network stack on the machine, and eventually the machine's hardware.
这让你只有这个选择:
- 设置一个将为您存储连接实例的 bean,我们称它为
myConnectionRegistry
,此 bean 的范围应为单例并注入所有 java 委托(服务任务实现)
- 在第一个任务中,您创建了连接,然后将其注册到
myConnectionRegistry
中,使用类似 connectionRegistry.register(conn, wfId)
的方式将连接实例添加到私有映射中....
- 在后续任务中,您使用从私有映射中获取连接对象的方法从同一个 bean 检索任务,如果没有在映射中注册连接对象则抛出异常
- 有一个在该异常上被触发的边界事件,并做任何必要的事情来确保数据完整性(例如我在评论中描述的用例)
- 在最后一个服务任务中,取消注册你的连接(你也应该关闭它)以防止内存泄漏
- 确保在设计解决方案时考虑数据库池...等!
干杯!
您可以在 Java 中使用 Thradlocal 将连接对象传递给不同的服务任务。
例如使用如下所示的 Base class 并从中扩展每个服务任务。然后您可以设置 dbConnection 并在需要时使用 get 方法使用。
public class BaseServiceTask
{
public static final ThreadLocal<Connection> localConnectionContext = new ThreadLocal<Connection>();
public static void initDBConnector(Connection dbConn)
{
localConnectionContext.set(dbConn);
}
public static Connection getDBConnector()
{
return localConnectionContext.get();
}
}
通知:
这种方法假设所有服务任务都在同一个线程中执行,这个特定问题就是这种情况,但是一旦你包含了一些用户任务/计时器(或任何异步逻辑),这就不再是一个可行的解决方案了!
我想使用 Activiti BPMN 流程来完成一些数据库更新任务。我的流程如下
开始事件 -> 服务任务 1 -> 服务任务 2 -> 服务任务 3 -> 结束事件
在服务任务 1 的服务实现 class 中:我为 MySQL 数据库创建了一个 java.sql.Connection。我需要将相同的 Connection 对象传递给服务任务 2 和服务任务 3。基本上,这两个 classes 将使用相同的 Connection 对象为数据库执行一些插入操作。
我尝试如下(dbConn 是包含 java.sql.Connection 类型 dbConnection 的 Class)
execution.setVariable("DBConn",dbConn);
但是它给出了一个异常,因为连接对象是不可序列化的。
"org.activiti.engine.ActivitiException: Couldn't serialize value"
那么在进程的服务任务之间传递此类不可序列化变量的最佳方式是什么?或者有什么方法可以在一个地方为多个服务任务定义这样的公共对象,并在服务任务中使用它们(类似于流程的全局变量)
首先,您应该知道,一旦根据 this.
创建了连接实例,就绝对没有办法对其进行序列化。The reason is that a connection uses a network resource (such as a TCP/IP socket) which uses the network stack on the machine, and eventually the machine's hardware.
这让你只有这个选择:
- 设置一个将为您存储连接实例的 bean,我们称它为
myConnectionRegistry
,此 bean 的范围应为单例并注入所有 java 委托(服务任务实现) - 在第一个任务中,您创建了连接,然后将其注册到
myConnectionRegistry
中,使用类似connectionRegistry.register(conn, wfId)
的方式将连接实例添加到私有映射中.... - 在后续任务中,您使用从私有映射中获取连接对象的方法从同一个 bean 检索任务,如果没有在映射中注册连接对象则抛出异常
- 有一个在该异常上被触发的边界事件,并做任何必要的事情来确保数据完整性(例如我在评论中描述的用例)
- 在最后一个服务任务中,取消注册你的连接(你也应该关闭它)以防止内存泄漏
- 确保在设计解决方案时考虑数据库池...等!
干杯!
您可以在 Java 中使用 Thradlocal 将连接对象传递给不同的服务任务。
例如使用如下所示的 Base class 并从中扩展每个服务任务。然后您可以设置 dbConnection 并在需要时使用 get 方法使用。
public class BaseServiceTask
{
public static final ThreadLocal<Connection> localConnectionContext = new ThreadLocal<Connection>();
public static void initDBConnector(Connection dbConn)
{
localConnectionContext.set(dbConn);
}
public static Connection getDBConnector()
{
return localConnectionContext.get();
}
}
通知:
这种方法假设所有服务任务都在同一个线程中执行,这个特定问题就是这种情况,但是一旦你包含了一些用户任务/计时器(或任何异步逻辑),这就不再是一个可行的解决方案了!