JBPM解析配置文件方法-讲解
这一次阅读,我们来研究一下上一节遗留下来的问题.JBPM是如何实现解析配置文件的.具体的方法在ConfigurationParser类中,我把方法分成了几部分来讲述,接下来我们一步步来分析.
public Object parseDocument(Document document, Parse parse) {
// if the default environment factory was already set in the parse
//将先前压进Stack的ConfigurationImpl.class找出来.
ConfigurationImpl configuration = parse.contextStackFind(ConfigurationImpl.class);
Element documentElement = document.getDocumentElement();
if (documentElement != null) {
// this code will be called for the original jbpm.cfg.xml document as
// well as for the imported documents. only one of those can specify
// a spring-cfg. for sure no 2 config files can specify different jndi-names
String spring = XmlUtil.attribute(documentElement, "spring");//是否支持Spring
if ("enabled".equals(spring)) {
configuration.springEnabled();
}
// this code will be called for the original jbpm.cfg.xml document as
// well as for the imported documents. only one of those can specify
// a jndi-name. for sure no 2 config files can specify different jndi-names
String jndiName = XmlUtil.attribute(documentElement, "jndi-name");
if (jndiName!=null) {
if ( (configuration.getJndiName()!=null)
&& (!jndiName.equals(configuration.getJndiName()))
) {
parse.addProblem("duplicate jndi name specification: "+jndiName+" != "+configuration.getJndiName());
} else {
configuration.jndi(jndiName);
}
}
- 首先,parseDocument方法将先前压进Stack的ConfigurationImpl.class找出来.
- 接着获取document的根节点.
- 然后,对属性进行判断:是否支持Spring和判断jndi-name是否有重复.
//递归解析import,所有有相互引用的,使用递归解析是最好的处理方式. for (Element importElement : XmlUtil.elements(documentElement, "import")) {//解析import if (importElement.hasAttribute("resource")) { String resource = importElement.getAttribute("resource"); Parse importParse = createParse() .setResource(resource) .contextStackPush(configuration) .propagateContexMap(parse) .execute(); parse.addProblems(importParse.getProblems()); } } 这一部分代码似曾相识,我们回忆一下在ConfigurationImpl类中,也有类似的这段代码.功能也是一样的,解析配置文件.但这里是递归解析import,在所有有相互引用的解析中,使用递归解析是最好的处理方式.
接下来,我们逐行的看下代码,
- 首先获得属性resource中的资源名称.
- 然后创建一个解析对象,并将解析器放入其中(从Parse类中,我们可以理解到createParse()方法,是ConfigurationParser解析器放入解析对象Parse中,而不是Parser.).
- setResource()很好理解,是设置配置文件资源.
- contextStackPush(),则是将配置类放入堆栈中.
- propagateContexMap(parse),传播parse中使用的ContectMap,合并两个parse的ContextMap内容且使用同一个ContextMap.(这里我们怎么理解呢?可以研究下propagateContexMap ()方法的实现.)
注意,下面这部分代码在Parse类中.
public Parse propagateContexMap(Parse parse) {
if (parse.contextMap==null) {
parse.contextMap = new HashMap<String, Object>();
}
if (this.contextMap!=null) {
parse.contextMap.putAll(this.contextMap);//将this.contextMap放到parse.contextMap.
}
this.contextMap = parse.contextMap;//让this使用parse的contextMap.
return this;
}
- 最后就是execute()了,跟前文讲解ConfigurationImpl类中的解析方法一样.
Element processEngineElement = XmlUtil.element(documentElement, "process-engine-context"); if (processEngineElement != null) { WireDefinition processEngineContextDefinition = configuration.getProcessEngineWireContext().getWireDefinition(); parse.contextStackPush(processEngineContextDefinition); try { processEngineContextParser.parseDocumentElement(processEngineElement, parse); } finally { parse.contextStackPop(); } }
Element txCtxElement = XmlUtil.element(documentElement, "transaction-context"); if (txCtxElement != null) { WireDefinition transactionContextDefinition = configuration.getTransactionWireDefinition(); parse.contextStackPush(transactionContextDefinition); try { transactionContextParser.parseDocumentElement(txCtxElement, parse); } finally { parse.contextStackPop(); } } }
上面两部分是解析实质内容process-engine-context和transaction-context.
总结
在这一次阅读中,我们可以发现,一般情况下一个配置文件的结构是怎么样的,可以从parseDocument()方法的解析过程看出.
- 首先是解析一些属性.
- 然后是递归解析import.
- 接着是ProcessEngine上下文和事务上下文配置.
是否如此呢?我们可以打开一个JBPM配置文件看看便得到满意的结果.下面的配置文件除了属性部分是没有的,import,流程引擎上下文和事务上下文配置都是有的.如此看来,我们了解了JBPM是怎么解析配置文件的.
<?xml version="1.0" encoding="UTF-8"?>
<jbpm-configuration>
<import resource="jbpm.default.scriptmanager.xml" />
<import resource="jbpm.mail.templates.xml" />
<process-engine-context>
<repository-service />
<repository-cache />
<execution-service />
<history-service />
<management-service />
<identity-service />
<task-service />
<object class="org.jbpm.pvm.internal.id.DatabaseDbidGenerator">
<field name="commandService"><ref object="newTxRequiredCommandService" /></field>
</object>
<object class="org.jbpm.pvm.internal.id.DatabaseIdComposer" init="eager" />
<object class="org.jbpm.pvm.internal.el.JbpmElFactoryImpl" />
<types resource="jbpm.variable.types.xml" />
<address-resolver />
</process-engine-context>
<transaction-context>
<repository-session />
<db-session />
<message-session />
<timer-session />
<history-sessions>
<object class="org.jbpm.pvm.internal.history.HistorySessionImpl" />
</history-sessions>
<mail-session>
<mail-server>
<session-properties resource="jbpm.mail.properties" />
</mail-server>
</mail-session>
</transaction-context>
</jbpm-configuration>