美文网首页Java 杂谈程序员
说说如何在项目中引入 jBPM4 工作流框架以及遇到的坑儿

说说如何在项目中引入 jBPM4 工作流框架以及遇到的坑儿

作者: deniro | 来源:发表于2018-08-15 11:47 被阅读25次

    由于各种原因,我们需要在项目中引入 jBPM4 工作流框架,遇到了不少问题,今记录如下O(∩_∩)O

    1 引入步骤

    1.1 加入依赖包

    1. 非 Maven 项目,在 lib 包中加入 jbpm.jar。
    2. Maven 项目,加入以下配置:
    <dependency>
        <groupId>org.jbpm</groupId>
        <artifactId>jbpm</artifactId>
        <version>${jbpm.version}</version>
    </dependency>
    

    如果私服上没有,可以自行作为第三方库上传到私服后,再配置 pom.xml。

    1.2 集成到 Spring

    <!-- jbpm 集成进 Spring -->
    <bean id="springHelper" class="org.jbpm.pvm.internal.processengine.SpringHelper"
          lazy-init="default" autowire="default">
        <property name="jbpmCfg">
            <value>jbpm.cfg.xml</value>
        </property>
    </bean>
    
    <!-- 工作流引擎-->
    <bean id="processEngine" factory-bean="springHelper"
          factory-method="createProcessEngine"/>
    

    名为 springHelper 的 Bean 中可以配置一个 jbpmCfg 参数,用于自定义 jbpm 配置文件。该文件名为 jbpm.cfg.xml,默认放置在 classpath 路径下。

    1.3 配置 Hibernate

    因为 jBPM4 使用的是 Hibernate 进行持久化操作,所以我们必须在此配置 jBPM4 持久化映射文件:

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                <prop key="hibernate.temp.use_jdbc_metadata_defaults">${hibernate.temp.use_jdbc_metadata_defaults}</prop>
            </props>
        </property>
        ...
    
        <!-- 持久化 jBPM4 实体类-->
        <property name="mappingResources">
            <list>
                <value>jbpm.repository.hbm.xml</value>
                <value>jbpm.execution.hbm.xml</value>
                <value>jbpm.history.hbm.xml</value>
                <value>jbpm.task.hbm.xml</value>
                <value>jbpm.identity.hbm.xml</value>
            </list>
        </property>
    </bean>
    

    一般来说,通过以上步骤就可以通过注入,获取到 jBPM4 的 processEngine 引擎啦O(∩_∩)O哈哈~

    1.4 执行脚本

    在下载的 jbpm-4.4 包中,打开 install\jdbc\ 文件夹,依据实际的数据库类型,选择相应的脚本,初始化 jBPM 库表:

    2 兼容 Hibernate4+

    jBPM4 默认适配 Hibernate3,所以如果框架使用的是高版本的 Hibernate,那么就必须修改 jBPM4 的源代码做适配。

    下面以 Hibernate4 为例,我们需要修改 jBPM4 这 SpringProcessEngine 与 HibernateSessionDescriptor 两个类。

    修改后的 jBPM4 源代码如下:

    1、SpringProcessEngine.java

    public class SpringProcessEngine extends ProcessEngineImpl {
    
      private static final Log log = Log.getLog(SpringProcessEngine.class.getName());
    
      private static final long serialVersionUID = 1L;
    
      private ApplicationContext applicationContext;
    
      public static ProcessEngine create(ConfigurationImpl configuration) {
        SpringProcessEngine springProcessEngine = null;
    
        ApplicationContext applicationContext = null;
        if (configuration.isInstantiatedFromSpring()) {
          applicationContext = (ApplicationContext) configuration.getApplicationContext();
    
          springProcessEngine = new SpringProcessEngine();
          springProcessEngine.applicationContext = applicationContext;
          springProcessEngine.initializeProcessEngine(configuration);
    
          LocalSessionFactoryBean localSessionFactoryBean = springProcessEngine.get(LocalSessionFactoryBean.class);
          Configuration hibernateConfiguration = localSessionFactoryBean.getConfiguration();
          springProcessEngine.processEngineWireContext
              .getWireDefinition()
              .addDescriptor(new ProvidedObjectDescriptor(hibernateConfiguration, true));
    
          springProcessEngine.checkDb(configuration);
    
        } else {
          String springCfg = (String) configuration.getProcessEngineWireContext().get("spring.cfg");
          if (springCfg==null) {
            springCfg = "applicationContext.xml";
          }
          applicationContext = new ClassPathXmlApplicationContext(springCfg);
          springProcessEngine = (SpringProcessEngine) applicationContext.getBean
                  ("jbpmProcessEngine");
        }
    
        return springProcessEngine;
      }
    
      public EnvironmentImpl openEnvironment() {
        PvmEnvironment environment = new PvmEnvironment(this);
    
        if (log.isTraceEnabled())
          log.trace("opening jbpm-spring" + environment);
    
        environment.setContext(new SpringContext(applicationContext));
    
        installAuthenticatedUserId(environment);
        installProcessEngineContext(environment);
        installTransactionContext(environment);
    
        return environment;
      }
    
      @SuppressWarnings("unchecked")
      @Override
      public <T> T get(Class<T> type) {
        T candidateComponent = super.get(type);
    
        if (candidateComponent != null) {
          return candidateComponent;
        }
    
        String[] names = applicationContext.getBeanNamesForType(type);
    
        if (names.length >= 1) {
    
          if (names.length > 1 && log.isWarnEnabled()) {
            log.warn("Multiple beans for type " + type + " found. Returning the first result.");
          }
    
          return (T) applicationContext.getBean(names[0]);
        }
    
        return null;
      }
    
      @Override
      public Object get(String key) {
        if (applicationContext.containsBean(key)) {
          return applicationContext.getBean(key);
        }
    
        return super.get(key);
      }
    }
    

    2、HibernateSessionDescriptor.java

    public class HibernateSessionDescriptor extends AbstractDescriptor {
    
        private static final long serialVersionUID = 1L;
        private static final Log log = Log.getLog(HibernateSessionDescriptor.class.getName());
    
        protected String factoryName;
        protected boolean useCurrent = false;
        protected boolean tx = true;
        protected boolean close = true;
        protected String standardTransactionName;
        protected String connectionName;
    
        public Object construct(WireContext wireContext) {
            EnvironmentImpl environment = EnvironmentImpl.getCurrent();
            if (environment == null) {
                throw new WireException("no environment");
            }
    
            // get the hibernate-session-factory
            SessionFactory sessionFactory = null;
            if (factoryName != null) {
                sessionFactory = (SessionFactory) wireContext.get(factoryName);
            } else {
                sessionFactory = environment.get(SessionFactory.class);
            }
            if (sessionFactory == null) {
                throw new WireException("couldn't find hibernate-session-factory " + (factoryName != null ? "'" + factoryName + "'" : "by type ") + "to open a hibernate-session");
            }
    
            // open the hibernate-session
            Session session = null;
            if (useCurrent) {
                if (log.isTraceEnabled()) log.trace("getting current hibernate session");
                session = sessionFactory.getCurrentSession();
    
            } else if (connectionName != null) {
                Connection connection = (Connection) wireContext.get(connectionName);
                if (log.isTraceEnabled())
                    log.trace("creating hibernate session with connection " + connection);
                session = (Session)sessionFactory.openStatelessSession(connection);
            } else {
                if (log.isTraceEnabled()) log.trace("creating hibernate session");
                session = sessionFactory.openSession();
            }
    
            StandardTransaction standardTransaction = environment.get(StandardTransaction.class);
            if (standardTransaction != null) {
                HibernateSessionResource hibernateSessionResource = new HibernateSessionResource(session);
                standardTransaction.enlistResource(hibernateSessionResource);
            }
    
            return session;
        }
    
        public Class<?> getType(WireDefinition wireDefinition) {
            return SessionImpl.class;
        }
    
        public void setFactoryName(String factoryName) {
            this.factoryName = factoryName;
        }
    
        public void setTx(boolean tx) {
            this.tx = tx;
        }
    
        public void setStandardTransactionName(String standardTransactionName) {
            this.standardTransactionName = standardTransactionName;
        }
    
        public void setConnectionName(String connectionName) {
            this.connectionName = connectionName;
        }
    
        public void setUseCurrent(boolean useCurrent) {
            this.useCurrent = useCurrent;
        }
    
        public void setClose(boolean close) {
            this.close = close;
        }
    }
    

    3 兼容 Activiti5+

    你没有看错,有的项目就是这么奇葩,已经有 Activiti5 咯,还需要集成进 jBPM4……

    这两套框架都是同一个架构师 Tom Baeyens 负责的,可谓是一脉相承,所以一些基本 Bean 的命名都是相同的,比如流程引擎 Bean 都叫做 processEngine。因此如果直接按照上述配置,就会出现 Spring Bean 命名冲突的问题。

    1、重命名 jBPM 工作流引擎 Bean

    <!-- 工作流引擎-->
    <bean id="jbpmProcessEngine" factory-bean="jbpmSpringHelper"
          factory-method="createProcessEngine"/>
    

    2、在 注入时使用该名称(比如这里取名为 jbpmProcessEngine)

    4 非 Spring 环境

    是的,有的项目非常老,连 Spring 框架都没有用,纳尼……

    可以写一个工具类,把流程引擎对象作为常量返回:

    public class WorkflowUtils {
    
    
        //工作流引擎
        private static ProcessEngine PROCESS_ENGINE;
        
        //配置文件前缀
        public static final String SPRING_CONFIG_PREFIX = "classpath:resources/";
    
    
        /**
         * 获取工作流引擎
         *
         * @return
         */
        public static ProcessEngine getProcessEngine() {
            if (PROCESS_ENGINE == null) {
                ApplicationContext applicationContext = new ClassPathXmlApplicationContext
                        (SPRING_CONFIG_PREFIX + "spring-hibernate.xml",
                                SPRING_CONFIG_PREFIX + "spring-jbpm" +
                                        ".xml");
    
                PROCESS_ENGINE = (ProcessEngine) applicationContext.getBean
                        ("jbpmProcessEngine");
            }
            return PROCESS_ENGINE;
        }
    }
    

    在此,我们利用 ApplicationContext 加载与 jBPM4 相关的配置文件,然后初始化 ProcessEngine,并设置为常量。这样,以后直接使用这个常量引擎对象就可以啦O(∩_∩)O哈哈~


    只要有耐心、细心和恒心,没有我们程序员解决不了的事儿O(∩_∩)O哈哈~

    相关文章

      网友评论

        本文标题:说说如何在项目中引入 jBPM4 工作流框架以及遇到的坑儿

        本文链接:https://www.haomeiwen.com/subject/inyibftx.html