`

Spring, Springmodules, JBPM持久化集成--优雅的回调(转)

阅读更多
【转自:http://ginge.iteye.com/blog/165996】
Spring, Springmodules, JBPM持久化集成--优雅的回调

本系列文章假设阅者具备以下知识:
1,ThreadLocal相关知识
2,Spring持久化,事务管理相关知识
3,Hibernate 持久化相关知识
4,Jbpm 持久化相关知识
5,Springmodules项目相关知识
6,相关J2EE知识


且具备以下材料:
1,Spring源代码
2,Hibernate源代码
3,Jbpm源代码
4,Springmodules源代码


接触JBPM始于两年多前,当时还在广州一个公司实习,公司打算研发ITIL相关的项目,于是就开始知道了工作流,也就开始接触了JBPM,但是对比过不同的工作流,还是觉得JBPM有前途,因为它隶属于JBOSS,社区活跃。当然,和其他JBOSS项目一样缺乏足够的支持,最有用的就是附带的User Guide Reference。


现在受Spring影响太深了,接触什么项目想到的首先就是尝试和Spring集成。接触JBPM也不例外,不过与JBPM和Spring的集成,已经有人做了,这个项目就是SpringModules-jbpm了,而且做的很优雅,充分体现了Spring提倡的Inversion of Control的美。


我尝试将这种美表述出来与大家分享,首先我会摘取Spring Modules手册里与JBPM集成的部分内容。跟着会引用一部分JBPM的手册里的相关章节和阅读一部分相关代码分析SpringModules集成的原理。最后谈一谈JBPM持久化与Spring事务管理的集成。相信能够让困惑于LazyLoading的朋友一些有益的启示。


一,SpringModules与JBPM的集成
<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xmlns:jee="http://www.springframework.org/schema/jee"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd   
            http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">  
    <!-- framework's contexts -->  
  
    <bean id="resource.PropertyConfigurer"  
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
        <property name="locations">  
            <list>  
                <value>classpath:jdbc.properties</value>  
            </list>  
        </property>  
    </bean>  
  
  
  
    <!-- JNDI DataSource for J2EE environments -->  
    <!--jee:jndi-lookup id="dataSource" jndi-name="java:/comp/env/jdbc/moss" /-->  
    <bean id="resource.DataSource"  
        class="org.apache.commons.dbcp.BasicDataSource"  
        destroy-method="close">  
        <property name="driverClassName"  
            value="${appserver.jdbc.driverClassName}" />  
        <property name="url" value="${appserver.jdbc.url}" />  
        <property name="username" value="${appserver.jdbc.username}" />  
        <property name="password" value="${appserver.jdbc.password}" />  
        <property name="maxActive" value="${appserver.jdbc.maxActive}" />  
        <property name="maxIdle" value="${appserver.jdbc.maxIdle}" />  
        <property name="maxWait" value="${appserver.jdbc.maxWait}" />  
        <property name="defaultAutoCommit"  
            value="${appserver.jdbc.defaultAutoCommit}" />  
        <property name="removeAbandoned"  
            value="${appserver.jdbc.removeAbandoned}" />  
        <property name="removeAbandonedTimeout"  
            value="${appserver.jdbc.removeAbandonedTimeout}" />  
    </bean>  
  
  
  
    <!-- Hibernate SessionFactory -->  
    <bean id="resource.SessionFactory"  
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
        <property name="dataSource" ref="resource.DataSource" />  
        <property name="configLocations">  
            <list>  
                <value>classpath*:hibernate.cfg.xml</value>  
            </list>  
        </property>  
    </bean>  
       
    <!-- jBPM configuration -->  
    <bean id="resource.JbpmConfiguration"  
        class="org.springmodules.workflow.jbpm31.LocalJbpmConfigurationFactoryBean">  
        <property name="configuration" value="classpath:jbpm.cfg.xml" />  
        <property name="createSchema" value="false" />  
        <property name="sessionFactory">  
          <ref local="resource.SessionFactory"/>  
        </property>  
    </bean>  
       
    <!-- jBPM template -->  
    <bean id="resource.JbpmTemplate"  
        class="org.springmodules.workflow.jbpm31.JbpmTemplate">  
        <constructor-arg index="0" ref="resource.JbpmConfiguration" />  
    </bean>  
  
</beans>  


LocalJbpmConfigurationFactoryBean

最重要的就是LocalJbpmConfigurationFactoryBean了,相信Spring的用户对这样的Bean都很熟悉。根据jbpmConfiguration配置文件和提供的sessionFactory,它会创建一个可以与提供的流程定义协同工作的jBPM Configuration。sessionFactory属性可有可无,如果提供了,将会使用sessionFactory提供的session进行数据库操作。但是如果注入了sessionFactory,就可以重用Spring提供的事务管理架构,且不需要对jBPM做任何代码修改,还可以结合使用OpenSessionInView模式,好处显而易见吧。


JbpmTemplate and JbpmCallback

像Spring与Hibernate,JDBC的集成有相应的Template, Callback类一样,Spring与Jbpm的集成也有JbpmTemplate和JbpmCallback,且默认提供了一些便利方法供用户使用,例如findProcessInstance,findPooledTaskInstances,saveProcessInstance,signal等。

因为JbpmTemplate继承了JbpmAccessor,父类JbpmAccessor实现了InitializingBean,所以Spring在初始化这个JbpmTemplate时会调用afterPropertiesSet方法来配置JbpmTemplate所使用到的HibernateTemplate。JbpmAccessor 还做了一些访问异常的转换操作。



这两个类协同起来要完成的事情是,如果提供了SessionFactory或者
HibernateTemplate, 在JbpmCallback里的doInJbpm方法之前注入SessionFactory提供的hibernate session。如果没有提供SessionFactory,那么持久化的操作还是交回给Jbpm。如果存在SessionFactory, session的打开,关闭就由SessionFactory管理。否则由JBPM自身的持久化逻辑来维护。
这部分逻辑可以查看HibernateTemplate的execute方法:
public Object execute(final JbpmCallback callback) {   
        final JbpmContext context = getContext();   
  
        try {   
            // use the hibernateTemplate is present and if needed   
            if (hibernateTemplate != null && hasPersistenceService) {   
  
                // use hibernate template   
                return hibernateTemplate.execute(new HibernateCallback() {   
                    /**  
                     * @see org.springframework.orm.hibernate3.HibernateCallback#doInHibernate(org.hibernate.Session)  
                     */  
                    public Object doInHibernate(Session session) throws HibernateException, SQLException {   
                        // inject the session in the context   
                        context.setSession(session);   
                        return callback.doInJbpm(context);   
                    }   
                });   
            }   
  
            // plain callback invocation (no template w/ persistence)   
            return callback.doInJbpm(context);   
  
        }   
        catch (JbpmException ex) {   
            throw convertJbpmException(ex);   
        }   
        finally {   
            releaseContext(context);   
        }   
  
    }  

本篇尝试探讨SpringModules集成的背后逻辑,这涉及到JbpmContext持久化的哲学。 

  JbpmContext持久化管理的哲学是,如果用户提供Context数据库连接,那么用户就要管理该数据库的打开与关闭。如果使用JbpmContext自己产生的持久化服务,那么该服务就要管理与持久化相关的操作。很像各人自扫门前雪,哪管他人瓦上霜。

这里首先引用Jbpm User Guide里面关于持久化的描述:
引用

7.5. User provided stuff

You can also programmatically provide JDBC connections, hibernate sessions and hibernate session factories to jBPM.

When such a resource is provided to jBPM, it will use the provided resources rather then the configured ones.

The JbpmContext class contains some convenience methods to inject resources programmatically. For example, to provide a JDBC connectio to jBPM, use the following code:

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
Connection connection = ...;
jbpmContext.setConnection(connection);

// invoke one or more persistence operations

} finally {
jbpmContext.close();
}

the JbpmContext class has following convenience methods for providing resource programmatically:

JbpmContext.setConnection(Connection);
JbpmContext.setSession(Session);
JbpmContext.setSessionFactory(SessionFactory);

上面的文字Jbpm就声明了它只管它自己的持久化逻辑,至于别人塞过来的,对不起,那是别人的事情。我想,很多人在看到Jbpm User guide的这些文字的时候,都会想弄明白藏在这些文字背后的逻辑的。  
  Jbpm中所有数据库操作的入口都是JbpmContext,各种的数据库操作例如save,JbpmContext都会委派给不同的xxxSession,例如GraphSession,TaskMgmtSession等来处理。

假设这个操作是loadTaskInstance,我将整个过程就缩小到我们关心的领域,一个是连接的打开,另外一个是连接的关闭:

第一部分,Session的打开:

【位置JbpmContext】
public TaskInstance loadTaskInstance(long taskInstanceId) {   
    return getTaskMgmtSession().loadTaskInstance(taskInstanceId);   
}   
  
public TaskMgmtSession getTaskMgmtSession() {   
    PersistenceService persistenceService = getPersistenceService();   
    if (persistenceService==null) return null;   
    return (persistenceService!=null ? persistenceService.getTaskMgmtSession() : null);  

这个PersistenceService就是jbpm.cfg.xml里面配置的org.jbpm.persistence.db.DbPersistenceService了,在上面getTaskMgmtSession这个方面里面PersistenceService就返回了一个带有一个Hibernate session的TaskMgmtSession了。

如下所示:
【位置DbPersistenceService】
public TaskMgmtSession getTaskMgmtSession() {   
    if (taskMgmtSession==null) {   
      Session session = getSession();   
      if (session!=null) {   
        taskMgmtSession = new TaskMgmtSession(session);   
      }   
    }   
    return taskMgmtSession;   
  }  


好了,到此我们就差不多达到Jbpm管理Session的环节了,我们再进入到getSession方法,看看它到底做了什么事情:

准备工作:1)以下是会涉及的布尔变量,以及其默认值:
【位置DbPersistenceService】
Connection connection = null;   
  boolean mustConnectionBeClosed = false;   
  
  Transaction transaction = null;   
  boolean isTransactionEnabled = true;   
  boolean isCurrentSessionEnabled = false;   
  boolean isRollbackOnly = false;   
  
  Session session;   
  boolean mustSessionBeFlushed = false;   
boolean mustSessionBeClosed = false;  

准备工作2)由于DbPersistenceService只有一个Constructor,也就是
【位置DbPersistenceService】
public DbPersistenceService(DbPersistenceServiceFactory persistenceServiceFactory) {
    this.persistenceServiceFactory = persistenceServiceFactory;
    this.isTransactionEnabled = persistenceServiceFactory.isTransactionEnabled();
    this.isCurrentSessionEnabled = persistenceServiceFactory.isCurrentSessionEnabled();
  } 

在这里我们就知道了,进行数据库操作所用到Session,SessionFactory就只能通过相关的Setter和Getter方法来取到了。  现在进入这个方法:
【位置DbPersistenceService】
public Session getSession() {   
    if ( (session==null)   
         && (getSessionFactory()!=null)    
       ) {   
      Connection connection = getConnection(false);    
      if (isCurrentSessionEnabled) {   
        session = getSessionFactory().getCurrentSession();   
        mustSessionBeClosed = false;   
        mustSessionBeFlushed = false;   
        mustConnectionBeClosed = false;   
      } else if (connection!=null) {   
        log.debug("creating hibernate session with connection "+connection);   
        session = getSessionFactory().openSession(connection);   
        mustSessionBeClosed = true;   
        mustSessionBeFlushed = true;   
        mustConnectionBeClosed = false;   
      } else {   
        log.debug("creating hibernate session");   
        session = getSessionFactory().openSession();   
        mustSessionBeClosed = true;   
        mustSessionBeFlushed = true;   
        mustConnectionBeClosed = false;   
      }   
         
      if (isTransactionEnabled) {   
        log.debug("beginning hibernate transaction");   
        transaction = session.beginTransaction();   
      }   
    }   
    return session;   
  }  

因为注入到JbpmContext的session和sessionFactory Setter方法都是将其注入到persistenceService里面的 在上面这个方法里
1)如果用户向JbpmContext提供了Session,那么会立刻返回该session,并且不会修改mustConnectionBeClosed,mustSessionBeClosed等的值。

2)如果用户向JbpmContext提供了SessionFactory,在getConnection时将mustConnectionBeClosed设置成了false,另外使用返回的Connection创建了一个Hibernate Session,即session = getSessionFactory().openSession(connection);紧接着将mustSessionBeClosed和mustSessionBeFlushed设置成了true。
分享到:
评论
2 楼 zhu20198838 2008-10-06  
文章很不错,谢谢
1 楼 kencool 2008-03-05  
原文被分成了两部分,特转来合并,方便阅览

相关推荐

    spring-modules-jbpm31-0.6.jar

    spring-modules-jbpm31-0.6.jar,spring整合jbpm的jar包

    Spring-Jbpm-JSF-Example.pdf

    标题与描述提到的“Spring-Jbpm-JSF-Example.pdf”是一个示例项目,展示了如何将Spring框架、Jbpm工作流引擎和JSF(JavaServer Faces)技术集成在一起。此项目通过一个简单的应用实例,演示了如何运行基本的工作流程...

    jbpm下载 jbpm-jpdl-suite-3.2GA -(5)分开压缩(共5个文件)

    jbpm-jpdl-suite-3.2GA -(5)分开压缩(共5个文件)jbpm下载 jbpm-jpdl-suite-3.2GA -(5)分开压缩(共5个文件)jbpm下载

    Spring与JBPM4的集成.docx

    ProcessEngineContext是指JBPM4的流程引擎上下文,Hibbernate Session Factory是指JBPM4的持久化机制,Transaction Context是指JBPM4的事务管理机制,Spring Context是指JBPM4中的Spring框架上下文。这些机制的集成...

    jbpm-jpdl-suite-3.2.3安装配置.doc

    在配置jbpm-jpdl-suite-3.2.3的过程中,需要注意以下几个关键步骤: 1. **环境准备**: - 首先,确保你已经安装了JDK 1.6,因为jbpm-jpdl-suite-3.2.3需要依赖Java运行环境。 - 安装Ant 1.7.1,这是一个Java编译...

    JBPM-----PPT

    - **持久化机制**:介绍JBPM如何利用数据库存储流程实例和变量,确保数据安全和流程恢复。 4. **平台特性:JBPM_(4)_Platform.ppt** - **jbpm-gwt-console**:一个基于GWT的Web管理控制台,用于监控和管理流程...

    jbpm-starters-kit-3.1.2.part2.rar

    jbpm-starters-kit-3.1.2插件,jbpm-starters-kit-3.1.2插件,jbpm-starters-kit-3.1.2插件,jbpm-starters-kit-3.1.2插件,jbpm-starters-kit-3.1.2插件,jbpm-starters-kit-3.1.2插件,共两卷

    jbpm-jpdl-suite-3.2.3的安装配置

    2. **jbpm-jpdl-designer-3.1.2.zip**:这是一个基于Eclipse的图形化流程设计工具,支持流程的可视化定制,避免直接编辑XML文件。同时,它还具有流程定义上传功能,方便将新定义的流程发布到jPDL系统。 3. **jbpm-...

    spring与jbpm的集成包(符集成方法)

    Spring 和 JBPM 集成是一项关键的技术任务,它允许开发者在基于 Spring 的应用程序中无缝地集成业务流程管理(BPM)功能。JBPM 是一个开源的 BPM 解决方案,提供工作流服务、流程建模、执行和监控等功能。下面我们将...

    jbpm-jpdl-designer-site-3.1.7.zip

    jbpm-jpdl-designer-site-3.1.7.zip jbpm-jpdl-designer-site-3.1.7.zip jbpm-jpdl-designer-site-3.1.7.zip

    jbpm-jpdl-suite-3.2.3.zip

    jbpm-jpdl-suite-3.2.3.zipjbpm-jpdl-suite-3.2.3.zipjbpm-jpdl-suite-3.2.3.zipjbpm-jpdl-suite-3.2.3.zipjbpm-jpdl-suite-3.2.3.zipjbpm-jpdl-suite-3.2.3.zipjbpm-jpdl-suite-3.2.3.zipjbpm-jpdl-suite-3.2.3....

    jbpm的入门1--简单实例

    总的来说,jbpm是一个强大的工具,它使得业务流程的管理和自动化变得简单。通过这个简单的入门实例,你将了解到如何设计、部署和运行一个基本的jbpm流程。随着深入学习,你可以利用jbpm构建复杂的业务流程系统,适应...

    jbpm-4.3-src.rar_bdf-jbpm4 src _jboss 4.3_jboss jbpm4.3_jbpm-4.3

    jbpm-4.3-src.rar_bdf-jbpm4 src _jboss 4.3_jboss jbpm4.3_jbpm-4.3 这个压缩包文件包含的是JBOSS jBPM4.3的源代码,这是一个用于业务流程管理(BPM)的开源框架。jBPM是一个强大的工具,它提供了流程定义、执行和...

    jbpm-jpdl-suite-3.2.GA.zip-6

    jbpm-jpdl-suite-3.2.GA.zip

    jbpm-workitems-5.1.0.Final-sources.jar

    jbpm-workitems-5.1.0.Final-sources.jar jbpm5 源码

    jbpm-jpdl-designer-nodeps-3.1.4

    "jbpm-jpdl-designer-nodeps-3.1.4" 是一个针对Jbpm工作流管理系统中的JPDL设计工具的无依赖版本,主要用于创建和编辑JPDL(Jbpm Process Definition Language)文件。该资源包含了该工具的详细文档、许可证协议以及...

    jbpm-bpmn2-5.1.0.Final.jar

    jbpm-bpmn2-5.1.0.Final.jar jbpm5

    jBPM4-app-forth4 源码实例 jbpm4

    3. **实体与持久化**:分析实体类和数据库表结构,理解jBPM4如何存储流程实例、任务和变量。 4. **任务处理**:研究任务服务接口(TaskService)的使用,掌握如何分配、领取和完成任务。 5. **监听器和回调**:查找...

    jbpm-3.1.2.zip_jbpm_jbpm 3.1.2_jbpm-3.1.2.rar_jbpm3.1.2_工作流

    jbpm-3.1.2.zip 文件包含了 jBpm 的一个重要版本——jBpm 3.1.2,这是一个开源的工作流管理系统,专为构建灵活且可扩展的业务流程解决方案而设计。jBpm 提供了一种方式,使得开发者能够用简单而强大的语言来表达业务...

Global site tag (gtag.js) - Google Analytics