`
salazar
  • 浏览: 30632 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

解决JBPM整合SPRING部署持久层疑问

    博客分类:
  • JBPM
阅读更多

       在研究JBPM,要应用到项目开发之中,由于系统使用spring作为业务层管理,而JBPM默认使用的hibernate作为持久层管理。我需要将它们集成在一起,幸运的是spring与hibernate本身就有完全兼容的集成应用方案,但是之中还是遇到不少问题。

      我这使用的JBPM版本是3.1.2,下载的包是jbpm-starters-kit-3.1.2.zip。

      首先要将JBPM持久层部分通过系统自动持久化(使用内存数据库hsqldb除外)。我们先将JBPM部署持久层需要的jar包摘出来,虽然JBPM应用需要不少jar包,但是部署持久层并不是需要很多,清单如下:
      

 

jar包 路径(BaseDir = jbpm-starters-kit-3.1.2) 说明
hibernate3 BaseDir \jbpm\lib\hibernate\ hibernate核心程序,版本3.1
spring 需要下载 Spring核心程序,这里使用的版本是2.0
jbpm-3.1.2 BaseDir \jbpm\build\ JBPM核心程序
dom4j-1.6.1 BaseDir \jbpm\lib\dom4j\ 支持解析xml核心程序
spring-modules-jbpm31 需要下载 spring与jbpm集成支持包
jboss-j2ee BaseDir \jbpm\lib\jboss\ JBOSS支持JBPM需要的java程序
cglib-2.1_2jboss BaseDir \jbpm\lib\jboss\

支持JOSS-J2EE和hibernate.tool.hbm2ddl,如果不使用会报错:
java.lang.NoClassDefFoundError: net/sf/cglib/proxy/CallbackFilter

bsh BaseDir \jbpm\lib\jboss\ 支持JOSS-J2EE,如果不使用会报错:bsh/EvalError
asm BaseDir \jbpm\lib\jboss\ 支持JOSS-J2EE,如果不使用会报错:
org/objectweb/asm/Type
antlr-2.7.5H3 BaseDir \jbpm\lib\jboss\ 支持JOSS-J2EE,如果不使用会报错:
antlr/ANTLRException
ehcache-1.1 BaseDir \jbpm\lib\hibernate\ 如果使用hibernate缓存则需要
ehcache-1.1 BaseDir \jbpm\lib\hibernate\ 如果使用hibernate缓存则需要

       除了上面的jar之外,还需要支持数据库的一些jar包。下面还需要JBPM提供的一些XML配置文件,具体清单如下:

 

文件名

路径

说明

default.jbpm.cfg.xml

jbpm-3.1.2,jar\org\jbpm\

jbpm主配置文件

ehcache.xml

BaseDir \jbpm\src\config.files\

如果使用hibernate缓存则需要配置

hibernate.cfg.xml

BaseDir \jbpm\src\config.files\

???,后面具体说明

     下面可以开始spring的配置了,要让系统自动持久化JBPM持久层,我们得先连上数据库,在spring中我们使用org.apache.commons.dbcp.BasicDataSource类作为数据源连接(需要commons-dbcp.jar支持)。例如:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
   <property name="driverClassName"   value="oracle.jdbc.driver.OracleDriver"></property>
   <property name="url"   value="jdbc:oracle:thin:@127.0.0.1:1521:oracle"></property>
    ... 省略若干
 </bean>

 

    然后我们使用spring集成hibernate来建立数据库会话工厂SessionFactory

  

<bean id="sessionFactory"
  class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
  <property name="dataSource">
           <ref local="dataSource" />
   </property>
  <property name="mappingLocations">
            <value>classpath*:org/jbpm/**/*.hbm.xml</value>
  </property>
  </bean>

 

    接下来我们要配置的就是JBPM比较关键的BEAN,即jbpmConfiguration;

<bean id="jbpmConfiguration" class="org.springmodules.workflow.jbpm31.LocalJbpmConfigurationFactoryBean">
          <property name="configuration" value="classpath:default.jbpm.cfg.xml" />
 </bean>

 

      配置其实很简单,只要将主配置xml文件放在src目录下,按照上面配置就可以,那么问题出来了,如何让它自动部署呢?

     JBPM本身提供jbpmConfiguration.createSchema方法来实现,而可以通过硬编码方式,或者在IOC配置jbpmConfiguration中加入〈property name="createSchema" value="true" /〉实现;

     我们使用第一种方式看看效果;我这里已经做好了一个监听ServletContextListener,实现方法如下:

public void contextInitialized(ServletContextEvent sce) {
	ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
  	JbpmConfiguration jbpmConfiguration = (JbpmConfiguration)ctx.getBean("jbpmConfiguration");
  	try{
  	 	jbpmConfiguration.createSchema();
  	}catch(Exception e) {
   		e.printStackTrace();
	}
}

     最终控制台输出为:org.hibernate.HibernateException: hibernate.cfg.xml not found,缺少这个配置文件;看来这种方式启动,这个文件是不可缺了;那么我们在src添上这个文件再运行看看效果;

      第二次控制台输出为:org.hibernate.HibernateException: The dialect was not set. Set the property hibernate.dialect. 这是怎么回事?

      从网上我也找到很多关于这样的配置,例如网上配置如下:

<bean id="jbpmConfiguration" class="org.springmodules.workflow.jbpm31.LocalJbpmConfigurationFactoryBean">
          <property name="configuration" value="classpath:default.jbpm.cfg.xml" />
          <property name="sessionFactory" ref="sessionFactory" />
         <property nname="createSchema" value="true"  />
 </bean>

 

      如果按照建立单独数据源dataSource,还是会出现这样的错误,除非使用hibernate.cfg.xml配置数据源;那么我们要使用单独的数据源部署应该怎么做?

        由于是 jbpmConfiguration.createSchema();方法报出的错误,我们先将错误详细信息打印出来:

 

org.hibernate.HibernateException: The dialect was not set. Set the property hibernate.dialect.
 at org.hibernate.dialect.Dialect.getDialect(Dialect.java:607)
 at org.hibernate.dialect.Dialect.getDialect(Dialect.java:629)
 at org.hibernate.tool.hbm2ddl.SchemaExport.<init>(SchemaExport.java:89)
 at org.hibernate.tool.hbm2ddl.SchemaExport.<init>(SchemaExport.java:64)
 at org.jbpm.persistence.db.DbPersistenceServiceFactory.getSchemaExport(DbPersistenceServiceFactory.java:76)
 at org.jbpm.persistence.db.DbPersistenceServiceFactory.createSchema(DbPersistenceServiceFactory.java:107)
 at org.jbpm.JbpmConfiguration.createSchema(JbpmConfiguration.java:415)

      

      看见在调用createSchema方法时,在方法体调用getSchemaExport方法中有段代码:

 

public synchronized SchemaExport getSchemaExport() {
    if (schemaExport==null) {
      log.debug("creating schema export");
      schemaExport = new SchemaExport(getConfiguration());
    }
    return schemaExport;
  }

 

     可以看见创建初始化SchemaExport对象,我们先看创建这个对象的参数getConfiguration()方法:

 public synchronized Configuration getConfiguration() {
    if (configuration==null) {
      String hibernateCfgXmlResource = null;
      if (JbpmConfiguration.Configs.hasObject("resource.hibernate.cfg.xml")) {  // 如果配置里含有resource.hibernate.cfg.xml项,那么读这个配置对应的文件
        hibernateCfgXmlResource = JbpmConfiguration.Configs.getString("resource.hibernate.cfg.xml");
      }
 ......省略若干
      configuration = HibernateHelper.createConfiguration(hibernateCfgXmlResource, hibernatePropertiesResource);
    }
    return configuration;
  }

 

     这里说读resource.hibernate.cfg.xml里的配置,我们可以打开JbpmConfiguration的配置文件default.jbpm.cfg.xml,看到确实是有这个配置,那么注释掉行吗?答案是不行的,最后在createConfiguration方法里还是会默认加载classpath:hibernate.cfg.xml,这是hibernate默认规定的,如果这个文件也没有,则就报错hibernate.cfg.xml not found;

      那么就是说这里初始化SchemaExport对象的环境变量就必须是从hibernate.cfg.xml这里配置的,对应到org.hibernate.tool.hbm2ddl.SchemaExport.89行方法调用getDialect方法出错;我们跟进到源码看见getDialect方法是这么写的:

public static Dialect getDialect() throws HibernateException {
      String dialectName = Environment.getProperties().getProperty( Environment.DIALECT );
      if ( dialectName == null ) throw new HibernateException( "The dialect was not set. Set the property hibernate.dialect." );
  ....
}

 

      意思是从环境变量属性中获取DIALECT 属性名称dialectName如果是空,则报错。
      看来我误会了JBPM例子的意思,使用JbpmConfiguration.createSchema方法的方式创建表结构要求是指定hibernate配置(也就是必须要在hibernate.cfg.xml里指定hibernate.properties配置信息),如果不配置hibernate-properties那么必然会出现这样缺少环境变量或缺少数据源信息的错误;

      如果是这样,那么解决这个问题?我们要先知道我们的目的是什么?

      就是将hibernate配置的持久层配置信息持久化到指定的数据库。那么JbpmConfiguration.createSchema

方法是不是自由JOSS-JBPM独有的呢?我们还是看源码分析,还是从这个方法入口进去,看见persistenceServiceFactory.createSchema();方法,继续跟进,发现getSchemaExport()方法,而这个方法是关键,即也是错误at org.jbpm.persistence.db.DbPersistenceServiceFactory.createSchema中指定的位置。好的这下我们可以再跟进发现一段代码schemaExport = new SchemaExport(getConfiguration());是它才能够调用create创建脚本方法,而SchemaExport并不是JBPM自身有的。

      这好像有些废话,用过hibernate的都知道hibernate本身就有Create-Schema功能,源码在org.hibernate.tool.hbm2ddl包下,配置属性为:

<bean id="sessionFactory"
  class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
  <property name="dataSource">
   <ref local="dataSource" />
  </property>
  <property name="mappingLocations">
   <value>classpath*:org/jbpm/**/*.hbm.xml</value>
  </property>
  <property name="hibernateProperties">
   <props><prop key="hibernate.hbm2ddl.auto">create</prop>  
   </props>
  </property>
 </bean>

 
        好的为了不再说废话hibernate.hbm2ddl.auto,大家可以自己查阅资料。再次部署测试......等待......终于创建成功了。但是还有个问题是hibernate.hbm2ddl.auto-create是在什么时候创建的呢?它是为什么能成功,而jbpmConfiguration.createSchema()不行?

      那我们依然看源码,既然是配在LocalSessionFactoryBean类下,就从这里看起。先思考,持久化肯定是在连接数据源,并生成会话之后才能够创建持久模型阿,又从源码上看这个类除了基本的set、get方法外,就只剩afterPropertiesSet中的buildSessionFactory。在此方法里我们可以发现一条代码:

   

if (this.hibernateProperties != null) {
    // Add given Hibernate properties to Configuration.
    config.addProperties(this.hibernateProperties);
   }

 

即添加hibernate配置属性,这就对应了IOC里配置的hibernateProperties项,再看最后的newSessionFactory方法中:

 

 Environment.verifyProperties( properties ); //在这里环境变量已经被注入进来了
  Properties copy = new Properties();
  copy.putAll( properties );
  PropertiesHelper.resolvePlaceHolders( copy );
  Settings settings = buildSettings( copy );   // 而最后将hibernateProperties配置,转化为对应的settings类

 return new SessionFactoryImpl(
    this,
    mapping,
    settings,
    getInitializedEventListeners()
   );

  

   跟进SessionFactoryImpl构造函数,发现在295行中有这么段代码:

   if ( settings.isAutoCreateSchema() ) new SchemaExport(cfg, settings).create(false, true); 这不就是自动持久化的判断吗?终于真像大白了,我们再总结下这个问题:

      1,采用JBPMConfiguration.createSchema方法,在初始化SchemaExport时用到的环境变量必须是从hibernate.cfg.xml来的,而这个文件如果不指定全hibernate信息,则会报错。

      2,如果让createSchema是在创建SessionFactory时,所用到的环境变量可以是从IOC容器里配置的,所以甚至可以不使用hibernate.cfg.xml文件。

    有些口水话.....

2
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics