在默認情況下,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容器的集成也是很方便的.