在JEE环境下整合Activiti5.8

 

Activiti5的前身是jBPM4,而jBPM5是由Drools Flow演化而来的,因此,对于大部分使用开源流程引擎的人来说,从jBPM3或者4升级到Activiti5比较容易,然而,自从Activiti诞生以来,随之而来的有一堆整合的问题:

 

  • Activiti5采用的持久层是MyBatis,而非行业内标准的JPA接口,而且两者耦合程度相当之高。所以对于采用Hibernate或者JPA作为持久层的系统,官方给出的解决方案就是将JPA和MyBatis捏合在一起,采用JPA的EntityManager来管理事务,其整合程度之恶心令人瞠目。
  • Acitiviti5采用的容器是Spring Container(包括配置文件),虽然官方也提供了脱离Spring容器的示例,但是无论从User Guide还是Example都对Spring提供了更好的支持,随之而来的问题就是,对于采用JEE环境的项目怎么办?这也是本文需要讨论的重点。

 

目前看来要想Use Activiti without Spring基本上有以下几种解决方案,如果大家有更好的解决方案欢迎补充:

 

  1. 将Spring整合进JEE环境,Spring框架本身是提供JEE的整合解决方案的,但是这种方法是无法without spring的,意味着开发者实际上是管理着Spring的容器。此方法究竟在事务上有无问题,我没有验证过。
  2. 采用原始的Process Engine,这种方案是最原始的方法,需要解决的问题是引擎在何时启动,又怎样保证引擎的最小化,如果每个EJB都去实例化一个引擎无疑性能将是低下的,因此对于JEE6的环境,可以采用@Singleton和@LocalBean的Bean对Process Engine进行初始化。

    /**
    * Session Bean implementation class ActivitiStarter
    */
    @Singleton
    @LocalBean
    public class ActivitiStarter {
       
        ProcessEngine processEngine = null;
    
        /**
         * Default constructor. 
         */
        public ActivitiStarter() {
           processEngine = ProcessEngines.getDefaultProcessEngine();
        }
    
    }
     
    <?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.xsd
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">
    
       <jee:jndi-lookup jndi-name="java:MysqlDS" id="dataSource" />
    
       <bean id="processEngineConfiguration"
          class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
          <property name="dataSource" ref="dataSource" />
          <property name="databaseSchemaUpdate" value="true" />
          <property name="databaseType" value="mysql" />
          <property name="jobExecutorActivate" value="false" />
       </bean>
    </beans>
     
    对于JEE5的环境,也许只能硬编码,写一个多线程的Singleton来对流程引擎进行初始化。

    public class ActivitiStart {
           
           private static ThreadLocal initHolder = new ThreadLocal();
           
           private static ProcessEngine engine;
    
           private static String DB_JNDI = "java:MysqlDS";
    
           public static ProcessEngine getEngineInstance () {
    
                  if (initHolder.get() == null) {
                         synchronized (initHolder) {
                                if (engine == null) {
                                       ProcessEngineConfiguration cfg = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
                                       cfg.setDataSourceJndiName(DB_JNDI);
                                       cfg.setTransactionsExternallyManaged(true);
                                       cfg.setKpbExecutorActivate(true);
                                       engine = cfg.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
                                }
                                initHolder.set(Boolean.TRUE);
                         }                     
                  }
                  return engine;
           }
    }
    这种方法比较原始,可以说基本上流程引擎是用编程式实现的,脱离了容器了,因此需要自己去维护引擎的初始化。 
  3. 最佳的解决方案其实是重写流程的初始化,讲流程引擎完全从Spring容器中脱离出来,放在JEE的容器中。好在已经有人做了这方面的工作
    基本的实现思路是利用jBoss Bean代替Spring Bean

    <deployment xmlns="urn:jboss:bean-deployer:2.0">
    
    	<bean name="ProcessEngineManager"
    		class="com.camunda.fox.activiti.enterprise.service.impl.ProcessEngineManager">
    		<property name="processEngineConfiguration"><inject bean="ProcessEngineConfiguration" /></property>
    		<property name="dataSourceJndiName">java:MysqlDS</property>
    	</bean>
    
    	<bean name="ProcessEngineConfiguration"
    		class="org.activiti.engine.impl.cfg.JtaProcessEngineConfiguration">
    		<property name="transactionManager"><inject bean="RealTransactionManager" /></property>		
    
    		<install method="setTransactionsExternallyManaged"><parameter><value>true</value></parameter></install>
    		<install method="setDatabaseSchemaUpdate"><parameter><value>true</value></parameter></install>
    		<install method="setMailServerHost"><parameter><value>localhost</value></parameter></install>
    		<install method="setMailServerPort"><parameter><value>2525</value></parameter></install>
    		<install method="setJobExecutorActivate"><parameter><value>true</value></parameter></install>
    	</bean>
    </deployment>
     在使用时只需要

    @Stateless
    public class StartProcessEjb implements StartProcessLocal, StartProcessRemote{    
    
    	@EJB RuntimeService runtimeService;    
    
    	public void startProcess() {     
    
    		runtimeService.startProcessInstanceByKey("someProcess");     
    
    	}
    }
     值得注意的是,这里的RuntimeService并不是引擎的原生实现的,而是第三方加载实现的。

 

目前看三种方式各自有利弊,没有哪种算是最完美的解决方案,比较完美的应该算是第三种,但是在事务的处理上,还需要进一步探讨。

第二、第三种方案的源码在附件中都有。

 

你可能感兴趣的:(spring,Activiti,ejb,jbpm,jee)