OFBiz業務方法里面,當執行一個service的時候,通常采用如下的方式:
LocalDispatcher dispatcher = dctx.getDispatcher();
Map<String, Object> result = dispatcher.runSync(getServiceName(), getContext());
LocalDispatcher是本地調度器,實現服務的同步異步調度和定時任務的調度。與服務調度相關的類圖如下:
LocalDispatcher是一個接口,實例化的都是GenericDispatcher類,ContextFilter實現了Servlet
Filter,會初始化一個GenericDispatcher,并將其存放在ServletContext中,以備整個應用使用。
在請求處理過程中,如果遇到service的event,那么EventHandler會使用LocalDispatcher執行service。
實際上GenericDispatcher只是一個Proxy,自己并不處理相關的調度工作,真正最苦最累的調度工作是由ServiceDispatcher完成的。下面具體研究一下Dispatcher同步和異步調用方法的實現代碼:
1.同步調用
通過dispatcher調用runSync方法,也即是調用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方法有三百多行,比較復雜,
但最終調用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文件中獲取相應的engine子類,如java的是org.ofbiz.service.engine.StandardJavaEngine
bsh的是org.ofbiz.service.engine.BeanShellEngine。
Java的StandardJavaEnignerunSync方法采用的是反射來執行相應的方法,如下:
Class<?> c = cl.loadClass(this.getLocation(modelService));
Method m = c.getMethod(modelService.invoke, DispatchContext.class, Map.class);
result = m.invoke(null, dctx, context);
不同的Engine實現的方式不一樣。
2. 異步調用
異步調用怎么實現的呢?實現異步的原理就是啟動一個線程來執行相應的業務邏輯,原方法直接返回,從而實現異步。具體實現的時候可以根據實際情況而定,比如將業務邏輯封裝成一個任務,將此任務放到一個任務鏈中,線程池采用先進先出的方式來選擇任務進行執行。OFBiz中怎么實現呢?具體查看GenericAsyncEngine的runAsync方法發現是通過一個生成一個Job來實現的:
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的執行,感興趣的可以看我的另一篇文章
OFBiz中Job的運行機制。