OFBiz業(yè)務(wù)方法里面,當(dāng)執(zhí)行一個service的時候,通常采用如下的方式:
LocalDispatcher dispatcher = dctx.getDispatcher();
Map<String, Object> result = dispatcher.runSync(getServiceName(), getContext());
LocalDispatcher是本地調(diào)度器,實現(xiàn)服務(wù)的同步異步調(diào)度和定時任務(wù)的調(diào)度。與服務(wù)調(diào)度相關(guān)的類圖如下:
LocalDispatcher是一個接口,實例化的都是GenericDispatcher類,ContextFilter實現(xiàn)了Servlet
Filter,會初始化一個GenericDispatcher,并將其存放在ServletContext中,以備整個應(yīng)用使用。
在請求處理過程中,如果遇到service的event,那么EventHandler會使用LocalDispatcher執(zhí)行service。
實際上GenericDispatcher只是一個Proxy,自己并不處理相關(guān)的調(diào)度工作,真正最苦最累的調(diào)度工作是由ServiceDispatcher完成的。下面具體研究一下Dispatcher同步和異步調(diào)用方法的實現(xiàn)代碼:
1.同步調(diào)用
通過dispatcher調(diào)用runSync方法,也即是調(diào)用GenericDispatcher的runSync方法:
/**
* @see org.ofbiz.service.LocalDispatcher#runSync(java.lang.String, java.util.Map)
*/
public Map<String, Object> runSync(String serviceName, Map<String, ? extends Object> context)
throws ServiceValidationException, GenericServiceException
{
ModelService service = ctx.getModelService(serviceName);
return dispatcher.runSync(this.name, service, context);
}
dispatcher實際是ServiceDispatcher對象。ServiceDispatcher的runSync方法有三百多行,比較復(fù)雜,
但最終調(diào)用service的是GenericEngine。
GenericEngine engine = this.getGenericEngine(modelService.engineName);
……
Map<String, Object> invokeResult = engine.runSync(localName, modelService, context);
GenericEngine是其工廠類GenericEngineFactory獲取的,這個Factory類非常簡單:
public class GenericEngineFactory {
protected ServiceDispatcher dispatcher = null;
protected Map<String, GenericEngine> engines = null;
public GenericEngineFactory(ServiceDispatcher dispatcher) {
this.dispatcher = dispatcher;
engines = FastMap.newInstance();
}
/**
* Gets the GenericEngine instance that corresponds to given the name
*@param engineName Name of the engine
*@return GenericEngine that corresponds to the engineName
*/
public GenericEngine getGenericEngine(String engineName) throws GenericServiceException {
Element rootElement = null;
try {
rootElement = ServiceConfigUtil.getXmlRootElement();
} catch (GenericConfigException e) {
throw new GenericServiceException("Error getting Service Engine XML root element", e);
}
Element engineElement = UtilXml.firstChildElement(rootElement, "engine", "name", engineName);
if (engineElement == null) {
throw new GenericServiceException("Cannot find a service engine definition for the engine name [" + engineName + "] in the serviceengine.xml file");
}
String className = engineElement.getAttribute("class");
GenericEngine engine = engines.get(engineName);
if (engine == null) {
synchronized (GenericEngineFactory.class) {
engine = engines.get(engineName);
if (engine == null) {
try {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class<?> c = loader.loadClass(className);
Constructor cn = c.getConstructor(ServiceDispatcher.class);
engine = (GenericEngine) cn.newInstance(dispatcher);
} catch (Exception e) {
throw new GenericServiceException(e.getMessage(), e);
}
if (engine != null) {
engines.put(engineName, engine);
}
}
}
}
return engine;
}
}
從配置文件serviceengine.xml文件中獲取相應(yīng)的engine子類,如java的是org.ofbiz.service.engine.StandardJavaEngine
bsh的是org.ofbiz.service.engine.BeanShellEngine。
Java的StandardJavaEnignerunSync方法采用的是反射來執(zhí)行相應(yīng)的方法,如下:
Class<?> c = cl.loadClass(this.getLocation(modelService));
Method m = c.getMethod(modelService.invoke, DispatchContext.class, Map.class);
result = m.invoke(null, dctx, context);
不同的Engine實現(xiàn)的方式不一樣。
2. 異步調(diào)用
異步調(diào)用怎么實現(xiàn)的呢?實現(xiàn)異步的原理就是啟動一個線程來執(zhí)行相應(yīng)的業(yè)務(wù)邏輯,原方法直接返回,從而實現(xiàn)異步。具體實現(xiàn)的時候可以根據(jù)實際情況而定,比如將業(yè)務(wù)邏輯封裝成一個任務(wù),將此任務(wù)放到一個任務(wù)鏈中,線程池采用先進(jìn)先出的方式來選擇任務(wù)進(jìn)行執(zhí)行。OFBiz中怎么實現(xiàn)呢?具體查看GenericAsyncEngine的runAsync方法發(fā)現(xiàn)是通過一個生成一個Job來實現(xiàn)的:
job = new GenericServiceJob(dctx, jobId, name, modelService.name, context, requester);
try {
dispatcher.getJobManager().runJob(job);
} catch (JobManagerException jse) {
throw new GenericServiceException("Cannot run job.", jse);
}
對于Job的執(zhí)行,感興趣的可以看我的另一篇文章
OFBiz中Job的運行機制。