`

jBPM中JbpmContext.close()一个值得注意的问题

    博客分类:
  • jBPM
阅读更多
在使用jBPM做开发的过程中, JbpmContextFilter 是一个非常方便的过滤器, 从源代码中我们可以看到:
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    String actorId = null;

    // see if we can get the authenticated swimlaneActorId
    if (servletRequest instanceof HttpServletRequest) {
      HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
      Principal userPrincipal = httpServletRequest.getUserPrincipal();
      if (userPrincipal != null) {
        actorId = userPrincipal.getName();
      }
    }

    JbpmContext jbpmContext = getJbpmConfiguration().createJbpmContext(jbpmContextName);
    try {
      if (isAuthenticationEnabled) {
        jbpmContext.setActorId(actorId);
      }
      filterChain.doFilter(servletRequest, servletResponse);
    } finally {
      jbpmContext.close();
    }
  }

它主要做了两个事情: 一个是在流程继续执行之前为我们创建了一个JbpmContext; 另一个工作就是流程执行之后完成jbpmContext的关闭. 而如果不使用这个Filter的话, 那么在我们的流程处理中,就需要自己做这两件事. 接着我们再看org.jbpm.JbpmContext.close()的代码:
public void close() {
    log.debug("closing jbpmContext " + toString());
    try {
      if (services!=null) {
        try {
          autoSave();
        } finally {
          services.close();
        }
      }
    } finally {
      if (jbpmConfiguration!=null) {
        jbpmConfiguration.jbpmContextClosed(this);
      }
    }
  }

在关闭之前都会执行自动保存.
从上面的分析我们可以看到, jbpm似乎没有提供我们处理流程内部异常的地方,它不管是否出现异常, 都会将我们的流程操作节点持久化到对应的jbpm数据库表中.本人就因为这个原因导致流程出现问题, 在我的一个流程运行过程中, 在某个审核步骤完成, 进入下一个task node的时候, 该Task节点的AssignmentHandler不幸抛出了异常, 按照我们的理解, 流程应该停留在前一步审核阶段, 但实际情况是审核节点已经被设置成完成状态, 而下一个task node的taskInstance也已经持久化到jbpm_taskinstance表中(只是处于未完成状态), 因为是在assign的时候出现的问题, 因此这个新创建的任务节点将成为一个无人处理的节点, 所有人都无法见不到它了.
出现上面的情况一点也不奇怪, 因为在TaskMgmtInstance的createTaskInstance方法中中有这样的代码:
// create the task instance
taskInstance.create(executionContext);

// if this task instance is created for a task, perform assignment
if (task!=null) {
  taskInstance.assign(executionContext);
}

它先创建taskInstance, 完成taskInstance的属性设置, 然后执行assign动作(异常就出现在这里), 在出现异常之后程序会回到JbpmContextFilter中,然后执行JbpmContext的close方法(该方法中完成所有新建和修改对象的持久化工作).

为了解决这个问题,就需要我们自己来处理jbpm引擎内部抛出的异常, 这一点jbpm做的非常好, 因为jpbm抛出的异常都是继承自JbpmException, 所以我们只要捕获该异常就可以了.而我们结束流程操作一般都是出现在这样几个地方:调用TaskInstance.end(), ProcessInstance.signal()以及相关的同名方法, 因此只要在调用这些方法的地方对异常进行捕获就可以了.
我将这几个方法放到工具类, 以方便调用:
public static void end(TaskInstance ti) {
	end(ti, (Transition) null);
}

public static void end(final TaskInstance ti, final String transitionName) {
	new JbpmOperation() {
		@Override
		void doExecute(JbpmContext ctx) {
			ti.end(transitionName);
		}
	}.execute();
}

public static void end(final TaskInstance ti, final Transition transition) {
	new JbpmOperation() {
		@Override
		void doExecute(JbpmContext ctx) {
			ti.end(transition);
		}
	}.execute();
}

public static void signal(final ProcessInstance pi) {
	new JbpmOperation() {
		@Override
		void doExecute(JbpmContext ctx) {
			pi.signal();
		}
	}.execute();
}


然后定义了一个回调的操作类用来处理在遇到JbpmException异常的时候告诉JbpmContext进行rollback:
/**
 * 用来处理流程异常, 如果流程本身出现异常(这些异常可能来自我们定义的各种assignmentHandler, actionHandler,
 * decisionHandler等),通过设置rollbackOnly来阻止其持久化
 * 
 * @author Macro Chen
 * @since Jun 3, 2008
 */
abstract class JbpmOperation {
	void execute() {
		JbpmContext ctx = JbpmUtils.getJbpmContext();
		try {
			doExecute(ctx);
		} catch (JbpmException e) {
			// 通过该方法让ctx提交的时候rollback
			ctx.setRollbackOnly();
			throw e;
		} finally {
			// 在filter中close
			// ctx.close();
		}
	}

	abstract void doExecute(JbpmContext ctx);

}
5
2
分享到:
评论
9 楼 oldoldabc 2014-04-01  
请问楼主,为什么您不用exception-handler节点来处理这些异常呢?或者是否还可以利用spring做一个拦截异常的AOP处理?
8 楼 stta04 2013-02-17  
stta04 写道
doExecute
stta04 写道
非常感谢,用这个方法解决了。

确切地说是借用了楼主的思路,但是对楼主的代码还存在几个问题:
第一:execute方法没有throws异常,那在其方法里怎么可以throw异常的?
第二:JbpmOperation 是一个抽象类是如何可以new实例化一个对象的?
还请楼主解答一下,先说声谢谢。^_^



第一:execute方法在捕捉异常后执行了throw e;
第二:JbpmOperation是一个抽象类,而
       new JbpmOperation() { 
        @Override 
        void doExecute(JbpmContext ctx) {             
             pi.signal(); 
        } 
    }
    其实就是new了一个匿名类,这个匿名类已经通过重写方式实现了抽象方法doExecute。
7 楼 stta04 2010-06-03  
doExecute
stta04 写道
非常感谢,用这个方法解决了。

确切地说是借用了楼主的思路,但是对楼主的代码还存在几个问题:
第一:execute方法没有throws异常,那在其方法里怎么可以throw异常的?
第二:JbpmOperation 是一个抽象类是如何可以new实例化一个对象的?
还请楼主解答一下,先说声谢谢。^_^
6 楼 stta04 2010-06-03  
非常感谢,用这个方法解决了。
5 楼 rmn190 2009-03-30  
谢谢楼主分享!

  我现在正在看这块的东西!
4 楼 john813 2008-06-21  
引用
jbpm中是有事务的, 但是它的处理是即使发生异常, 默认情况下它是commit, 因为他的关闭连接是放在finally{}中处理的, 它没有在发生异常的时候对该异常进行捕获然后设置rookbackOnly标识来让事务rollback.

是的哦。可能这就是为什么它的文档中说assign的异常是不会影响流程的。

我现在用spring控制事务,把jbpm的操作和其他dao的操作放在一个事务里。经过简单测试,貌似可以的。

我的测试方法是:
1,写一个操作jbpm流程的简单服务类SO,用来创建一个流程。
2,写一个简单的dao用来存储一个数据对象(VO)。
3,用spring配置该so和dao到一个事务中
4,定义一个简单流程,给启动后的第一个task节点增加一个AssignmentHandler。然后在这个AssignmentHandler中手工抛出一个RuntimeException。
5,最后运行。

结果,当启动流程后(processInstance.signal()),流程进入第一个task节点并触发AssignmentHandler执行。然后抛出那个异常。检查数据库,发现jbpm的表中没有新增任何记录。检查的表主要是jbpm_processinstance,jbpm_taskinstance。检查存储vo的表,也没有增加记录。

因此得出结论,通过事务,是可以保障流程状态和其他业务操作保持一致的。
3 楼 macrochen 2008-06-20  
引用
为什么不考虑用事务来控制 ?
jbpm的文档明确说了assign时候出现的异常是不会影响流程的流转状态的,需要自己处理。我也刚开始学jbpm。不知道是否可以通过事务来解决assign时候出现异常的问题。即如果assign出现异常,让事务机制控制整个流程状态回滚。

但不清楚assign是否会在单独的线程中执行,否则这样做也不行...

期待macrochen的回复。

jbpm中是有事务的, 但是它的处理是即使发生异常, 默认情况下它是commit, 因为他的关闭连接是放在finally{}中处理的, 它没有在发生异常的时候对该异常进行捕获然后设置rookbackOnly标识来让事务rollback.
2 楼 john813 2008-06-20  
为什么不考虑用事务来控制 ?
jbpm的文档明确说了assign时候出现的异常是不会影响流程的流转状态的,需要自己处理。我也刚开始学jbpm。不知道是否可以通过事务来解决assign时候出现异常的问题。即如果assign出现异常,让事务机制控制整个流程状态回滚。

但不清楚assign是否会在单独的线程中执行,否则这样做也不行...

期待macrochen的回复。
1 楼 llandyl 2008-06-05  
研究的深入呀。

相关推荐

    YOLO算法-城市电杆数据集-496张图像带标签-电杆.zip

    YOLO系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中,文件名末尾是部分类别名称; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值; 【注】可以下拉页面,在资源详情处查看标签具体内容;

    (177406840)JAVA图书管理系统毕业设计(源代码+论文).rar

    JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代码+论文) JAVA图书管理系统毕业设计(源代

    (35734838)信号与系统实验一实验报告

    内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。

    YOLO算法-椅子检测故障数据集-300张图像带标签.zip

    YOLO系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中,文件名末尾是部分类别名称; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值; 【注】可以下拉页面,在资源详情处查看标签具体内容;

    基于小程序的新冠抗原自测平台小程序源代码(java+小程序+mysql+LW).zip

    系统可以提供信息显示和相应服务,其管理新冠抗原自测平台小程序信息,查看新冠抗原自测平台小程序信息,管理新冠抗原自测平台小程序。 项目包含完整前后端源码和数据库文件 环境说明: 开发语言:Java JDK版本:JDK1.8 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/idea Maven包:Maven3.3 部署容器:tomcat7 小程序开发工具:hbuildx/微信开发者工具

    YOLO算法-俯视视角草原绵羊检测数据集-4133张图像带标签-羊.zip

    YOLO系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中,文件名末尾是部分类别名称; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值; 【注】可以下拉页面,在资源详情处查看标签具体内容;

    (171674830)PYQT5+openCV项目实战:微循环仪图片、视频记录和人工对比软件源码

    内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。

    新建 文本文档.docx

    新建 文本文档.docx

    hw06.zip

    hw06

    3. Kafka入门-安装与基本命令

    3. Kafka入门-安装与基本命令

    燃气管道施工资质和特种设备安装改造维修委托函.docx

    燃气管道施工资质和特种设备安装改造维修委托函.docx

    The state of AI 2024.pdf

    AI大模型研究相关报告

    lab02.zip

    lab02

    Unity视频插件AVPro的Win端2.2.3

    仅供学习使用,其他用途请购买正版资源AVPro Video Core Windows Edition 2.2.3 亲测可用的视频播放插件,能丝滑播放透明视频等.

    建设工程消防验收现场指导意见表.docx

    建设工程消防验收现场指导意见表.docx

    MVIMG_20241222_194113.jpg

    MVIMG_20241222_194113.jpg

    五相电机双闭环矢量控制模型-采用邻近四矢量SVPWM-MATLAB-Simulink仿真模型包括: (1)原理说明文档(重要):包括扇区判断、矢量作用时间计算、矢量作用顺序及切时间计算、PWM波的生成

    五相电机双闭环矢量控制模型_采用邻近四矢量SVPWM_MATLAB_Simulink仿真模型包括: (1)原理说明文档(重要):包括扇区判断、矢量作用时间计算、矢量作用顺序及切时间计算、PWM波的生成; (2)输出部分仿真波形及仿真说明文档; (3)完整版仿真模型:包括邻近四矢量SVPWM模型和完整双闭环矢量控制Simulink模型; 资料介绍过程十分详细,零基础手把手教学,资料已经写的很清楚

    YOLO算法-锡罐-牙罐-盖子打开数据集-179张图像带标签-锡罐-牙罐-盖子打开.zip

    YOLO系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中,文件名末尾是部分类别名称; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值; 【注】可以下拉页面,在资源详情处查看标签具体内容;

    java毕设项目之ssm基于JSP的乡镇自来水收费系统+jsp(完整前后端+说明文档+mysql+lw).zip

    项目包含完整前后端源码和数据库文件 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/idea Maven包:Maven3.3 服务器:tomcat7

Global site tag (gtag.js) - Google Analytics