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的運行機制