网上找了些关于Jbpm和Spring整合的文章,也对我帮助很大。但它们都是简单的配置,没有涉及到具体的使用和可能出现的问题(比如业务对象用的Annotation配置,而jbpm用的xml方式)。我把项目中的使用和经验写下来,也算做个总结吧。
整合使用的springmodules,它的原理其实很简单,使用Spring容器IoC提供的BeanFactory功能初始化jbpm的configuration,同时使用回调方法,整合jbpm context的create和close。我们先看springmodules提供的LocalJbpmConfigurationFactoryBean的配置文件:
<bean id="jbpmConfiguration" class="org.springmodules.workflow.jbpm31.LocalJbpmConfigurationFactoryBean"> <property name="sessionFactory" ref="sessionFactory" /> <property name="createSchema" value="false" /> <property name="configuration"> <value>classpath:jbpm.cfg.xml</value> </property> </bean>
而sessionFactory就是在spring中配置的bean,我使用了AnnotationSessionFactoryBean,它能够兼容xml方式的hibernate配置。LocalJbpmConfigurationFactoryBean实现了spring的InitializingBean, DisposableBean, FactoryBean, BeanFactoryAware, BeanNameAware,容器启动就会载入执行afterPropertiesSet方法,它在这个方法中进行了大量的初始化工作。
然后配置jbpmTemplate Bean,配置如下:
ref 了一个 contractDefinition 。它本身示例是通过 definitionLocation ,读取文件创建 definition 。而我们要和数据库的流程配合,就需要每次启动从数据库中读取最新的 definition ,所以我写了 DefinitionFactoryBean ,由这个 bean 启动时初始化 definition 然后注入到 template 中。 DefinitionFactoryBean 的配置和部分代码如下:
<bean id="contractJbpmTemplate" class="com.ibm.contract.process.ExtendJbpmTemplate"> <property name="jbpmConfiguration" ref="jbpmConfiguration" /> <property name="processDefinition" ref="contractDefinition" /> </bean>
这里我
提供的 JbpmTemplate 持有 jbpmConfiguration 引用,在它的 public Object execute(final JbpmCallback callback) 方法中进行回调处理,先创建 jbpmContext ,然后执行 callback 方法,然后在 finally 中 close jbpmContext 。
<bean id="contractDefinition" class="com.ibm.contract.process.DefinitionFactoryBean"> <property name="definitionName" value="contract" /> <property name="jbpmConfiguration" ref="jbpmConfiguration" /> </bean> public void afterPropertiesSet() throws Exception { if (this.definitionName == null) { throw new FatalBeanException("Property [definitionName] of class [" + ProcessDefinitionFactoryBean.class.getName() + "] is required."); } JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); GraphSession graphSession = jbpmContext.getGraphSession(); processDefinition = graphSession .findLatestProcessDefinition(definitionName); }
springmodules
有了这些基础设施,我们要进行测试就很简单。我都是使用spring的AbstractTransactionalDataSourceSpringContextTests进行autowire。比如进行deployTest:
public class DeployTest extends BaseProcessTestCase { private JbpmConfiguration jbpmConfiguration; public void setJbpmConfiguration(JbpmConfiguration jbpmConfiguration) { this.jbpmConfiguration = jbpmConfiguration; } public void testDeployProcessDefinition() throws FileNotFoundException { // 由jbpm自己 取得 jbpm 配置 // JbpmConfiguration config = JbpmConfiguration.getInstance(); // 创建一个 jbpm 容器 JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); // 由 processdefinition.xml 生成相对应的流程定义类 ProcessDefinition InputStream is = getClass().getResourceAsStream( "/contract/processdefinition.xml"); ProcessDefinition processDefinition = ProcessDefinition .parseXmlInputStream(is); // 利用容器的方法将流程定义数据部署到数据库上 jbpmContext.deployProcessDefinition(processDefinition); // 关闭 jbpmContext jbpmContext.close(); }
如果使用JbpmConfiguration config = JbpmConfiguration.getInstance();那么它会使用jbpm自己的机制,而对于使用了annotation方式配置的entity,就会报错。所以我注入配置的jbpmConfiguration,使用spring来进行session初始化。
对于jbpmTemplate的使用就很简单了,它已经注入了definition和context,可以调用它已经提供的一些具体方法,也可以调用execute,比如:
public TaskInstance loadTask(final long taskId) { return (TaskInstance) execute(new JbpmCallback() { public Object doInJbpm(JbpmContext context) { return context.loadTaskInstance(taskId); } }); }