在使用jBPM做开发的过程中, JbpmContextFilter 是一个非常方便的过滤器, 从源代码中我们可以看到: Java代码 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(); } } 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()的代码: Java代码 public void close() { log.debug("closing jbpmContext " + toString()); try { if (services!=null) { try { autoSave(); } finally { services.close(); } } } finally { if (jbpmConfiguration!=null) { jbpmConfiguration.jbpmContextClosed(this); } } } 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方法中中有这样的代码: Java代码 // create the task instance taskInstance.create(executionContext); // if this task instance is created for a task, perform assignment if (task!=null) { taskInstance.assign(executionContext); } // 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()以及相关的同名方法, 因此只要在调用这些方法的地方对异常进行捕获就可以了. 我将这几个方法放到工具类, 以方便调用: Java代码 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(); } 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: Java代码 /** * 用来处理流程异常, 如果流程本身出现异常(这些异常可能来自我们定义的各种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); } |
jBPM中JbpmContext.close()注意事项
最新推荐文章于 2012-07-06 14:11:00 发布