在默认情况下,jBPM包里有个jbpm.cfg.xml,这个就是他的配置文件,我们先看下它的内容.
<jbpm-configuration>
<import resource="jbpm.default.cfg.xml" />
<import resource="jbpm.tx.jta.cfg.xml" />
<import resource="jbpm.jpdl.cfg.xml" />
<import resource="jbpm.identity.cfg.xml" />
<import resource="jbpm.jobexecutor.cfg.xml" />
</jbpm-configuration>
这里,我们再继续看下jbpm.default.cfg.xml,看下配置文件到底是长啥样.
<process-engine-context>
<repository-service />
<repository-cache />
<execution-service />
<history-service />
<management-service />
<identity-service />
<task-service />
<hibernate-configuration>
<cfg resource="jbpm.hibernate.cfg.xml" />
</hibernate-configuration>
...........
</process-engine-context>
<transaction-context>
<repository-session />
<db-session />
<message-session />
<timer-session />
<history-session />
<mail-session>
<mail-server>
<session-properties resource="jbpm.mail.properties" />
</mail-server>
</mail-session>
</transaction-context>
这个配置文件主要包含了"process-engine-context'和 'transaction-context'的配置.
我们知道,现在都是讲究Dependency Inject (Inversion of Control),那么,我们这里到底是哪个类来实现repository-service呢?那配置mail-session又是怎么实例化的呢?
我们先来看下jBPM的IOC实现机制.
首先是Context接口,你可以从这里存储,获得对象.它的接口很简单.
Object get(String key);
<T> T get(Class<T> type);
Object set(String key, Object value);
你看可以从Context中获取到组件,对于IOC容器来说,一般情况下都会提供一种加载的方式,比如从xml文件进行加载、从资源文件进行加载。
Jbpm4是通过WireParser来解析xml,然后创建并把对象存放在WireContext. WireContext这个类负责存放,提取对象,内部用一个Map来存储已经创建的对象实例,可以简单得把他看成是IOC的一个实现类.
从WireContext的javadoc,我们可以看出,他主要是跟WireDefinition, Descriptor打
交道. WireContext里面
包含了一个WireDefinition,而WireDefinition里面包含了一系列的Descriptor.每个Descriptor负责创建和
初始化该对象. 比如我们可以看到IntegerDescriptor, FloatDescriptor, ObjectDescriptor等等.
我们来看下Descriptor的接口:
/**
* constructs the object.
* @param wireContext {@link WireContext} in which the object is created. This is also the {@link WireContext}
* where the object will search for other object that may be needed during the initialization phase.
* @return the constructed object.
*/
Object construct(WireContext wireContext);
/**
*called by the WireContext to initialize the specified object.
*/
void initialize(Object object, WireContext wireContext);
Descriptor对象的创建可以直接通过Java对象的实例化,比如(new IntegerDescriptor(..)),也可以通过xml的配置文件来实现.可以说我们更经常用xml来配置,所以就有了Binding的概念.
Binding类最主要的任务就是把XML DOM 到Java对象的转换. Bindings是把Binding归类了一下而已.
以下是Binding的接口.
public interface Binding {
String getCategory();
/** does this binding apply to the given element? */
boolean matches(Element element);
/** translates the given element into a domain model java object.
* Use the parse to report problems.
*/
Object parse(Element element, Parse parse, Parser parser);
}
如果想看实现,我们可以看下IdentityServiceBinding, RepositoryServiceBinding等等.这里注意下,在jBPM的实现当中,WireDescriptorBinding是根据tagName来解析的.
所以,从jBPM的xml配置文件,到ProcessEngine对象的构建,是这样的一个流程.
jbpm.cfg.xml –> jBPMConfigurationParser -> Binding –> Descriptor --> WireContext
或者更清楚的,我们可以看下下面这张图[
1].
我们不妨也看下ConfigurationTest测试.
public void testConfigurationServices() {
ProcessEngine processEngine = new Configuration()
.setXmlString(
"<jbpm-configuration>" +
" <process-engine-context>" +
" <repository-service />" +
" <execution-service />" +
" <management-service />" +
" </process-engine-context>" +
"</jbpm-configuration>"
)
.buildProcessEngine();
assertNotNull(processEngine);
assertNotNull(processEngine.getExecutionService());
assertNotNull(processEngine.getManagementService());
}
Configuration
类是jBPM的入口,你可以从
Configuration类中创建ProcessEngine,而从ProcessEngine中获取到RepositoryService,
ExecutionService, TaskService等等.
Configuration类里有两个实现类,一个是JbpmConfiguration,这是默认的jBPM自带的Configuration解析器,
另外一个是SpringConfiguration,这个是jBPM和Spring的集成.
在这里,我们就只看下JbpmConfiguration的实现,在JbpmConfiguration类里,我们可以看到他是这么去调用Parser来
解析xml的.
protected void parse(StreamInput streamSource) {
isConfigured = true;
JbpmConfigurationParser.getInstance()
.createParse()
.pushObject(this)
.setStreamSource(streamSource)
.execute()
.checkErrors("jbpm configuration " + streamSource);
}
在这里,我们可以看到,jbpm的配置文件是有两个元素组成的,一个是process-engine-context,另外一个是transaction-context. 其中process-engine-context里面的元素是包括了对外发布的服务,
比如repository-service, execution-service等等. 而transaction-context则包括了他的内部真正实现,比如repository-service对应repository-session.
也可以简单的把repository-servie看做是API, repository-session看做是SPI. 这样做的好处是,SPI的实现,对API一点影响都没有,很大程度上提供了一个容易集成的特性.
说到这里,应该对jBPM的IOC介绍的差不多了.我自己在用JBoss IDM project[2]来实现jBPM的Identity module时.需要增加如下的配置.
<jbpm-configuration>
<process-engine-context>
<jboss-idm-identity-session-factory jndi="java:/IdentitySessionFactory" />
</process-engine-context>
<transaction-context>
<jboss-idm-identity-session realm="realm://JBossIdentity" />
</transaction-context>
</jbpm-configuration>
于是,我需要增加以下的类来完成对象的创建和实例化. JbossIdmIdentitySessionFactoryBinding,JbossIdmIdentitySessionFactoryDescriptor,JbossIdmIdentitySessionBinding,
JbossIdmIdentitySessionDescriptor
然后,在jbpm.wire.bindings.xml里面注册我们新加的Binding.
从上面我们所说的,不难看出本身这个IOC的实现机制也是很简单的,而且也很容易扩展,如果说到时候和Spring, JBoss MC等IOC容器的集成也是很方便的.