OFBiz中services调用机制

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);
        }

转载自:http://www.cnblogs.com/Ivan-j2ee/archive/2012/04/13/2445414.html

时间: 2024-10-05 20:15:31

OFBiz中services调用机制的相关文章

转 OFBiz中services调用机制

OFBiz业务方法里面,当执行一个service的时候,通常采用如下的方式: LocalDispatcher dispatcher = dctx.getDispatcher();     Map<String, Object> result = dispatcher.runSync(getServiceName(), getContext()); LocalDispatcher是本地调度器,实现服务的同步异步调度和定时任务的调度.与服务调度相关的类图如下: LocalDispatcher是一个

Flex远程调用机制RemoteObject应用技巧

转自:http://zerozone.javaeye.com/blog/60846Flex远程调用RemoteObject出现的问题及解答: 本文主要讨论Flex在客户端与J2EE中间层数据交互的过程. Flex是构建RIA应用的客户端技术.它的优势在于提供了丰富的客户 端表现能力(例如增强UI组件.缓存.拖放.收缩/展开等),避免了基于HTML技术的缺陷:同时无缝地结合了J2EE技术在中间层(业务逻辑层)的强大优势. 尽 管MacroMedia提出的"体验经济"有宣传策略的成分,但R

android中的多线程机制

Google参考了Windows的消息处理机制,在Android系统中实现了一套类似的消息处理机制.学习Android的消息处理机制,有几个概念(类)必须了解: 1.       Message 消息,理解为线程间通讯的数据单元.例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程. 2.       Message Queue 消息队列,用来存放通过Handler发布的消息,按照先进先出执行. 3.       Handler Handler是Messa

[SpringBoot]深入浅出剖析SpringBoot中Spring Factories机制

微信号:GitShare微信公众号:爱折腾的稻草如有问题或建议,请在公众号留言[1] 前续 为帮助广大SpringBoot用户达到"知其然,更需知其所以然"的境界,作者将通过SpringBoot系列文章全方位对SpringBoot2.0.0.RELEASE版本深入分解剖析,让您深刻的理解其内部工作原理. 1.[SpringBoot]利用SpringBoot快速构建并启动项目 2.[SpringBoot]详解SpringBoot应用的启动过程 3.[SpringBoot]深入浅出剖析Sp

深入Windows内核——C++中的消息机制

<编程思想之消息机制>一文中我们讲了消息的相关概念和消息机制的模拟,本文将进一步聊聊C++中的消息机制. 从简单例子探析核心原理 在讲之前,我们先看一个简单例子:创建一个窗口和两个按钮,用来控制窗口的背景颜色.其效果如下: 图 2 :效果图 Win32Test.h #pragma once #include <windows.h> #include <atltypes.h> #include <tchar.h> //资源ID #define ID_BUTTO

深度解析VC中的消息传递机制

摘要:Windows编程和Dos编程,一个很大的区别就是,Windows编程是事件驱动,消息传递的.所以,要学好Windows编程,必须 对消息机制有一个清楚的认识,本文希望能够对消息的传递做一个全面的分析. 一.什么是消息? 消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉.一个消息,是系统定义的一个32位的值,他唯一的定 义了一个事件,向Windows发出一个通知,告诉应用程序某个事情发生了.例如,单击鼠标.改变窗口尺寸.按下键盘上的一个键 都会使Windows发送一个

linux套接字通信之recv中的缓存机制的研究

以前一直有这么一个小小的疑惑,当一个进程注册一个套接字后,如果这个套接字没有被调用recv函数接受数据包,那么这个套接字能接受到数据包吗? 或者这样说,如果我的程序注册了一个套接字去接受数据包,但是每收到一个数据包都需要很长一段时间处理,并且在处理数据包的途中recv函数使没有被调用的,那么如果程序再处理数据包的途中有数据包到来,那我的程序会不会漏过这些数据包(那个包到达的时候程序在处理别的包,而没有调用recv函数)? 答案是不会的.事实上linux中会为每个套接字建立缓存,当属于套接字的包到

windows和linux套接字中的select机制浅析

先来谈谈为什么会出现select函数,也就是select是解决什么问题的? 平常使用的recv函数时阻塞的,也就是如果没有数据可读,recv就会一直阻塞在那里,这是如果有另外一个连接过来,就得一直等待,这样实时性就不是太好. 这个问题的几个解决方法:1. 使用ioctlsocket函数,将recv函数设置成非阻塞的,这样不管套接字上有没有数据都会立刻返回,可以重复调用recv函数,这种方式叫做轮询(polling),但是这样效率很是问题,因为,大多数时间实际上是无数据可读的,花费时间不断反复执行

java中利用反射机制绕开编译器对泛型的类型限制

首先看下面这个例子 public static void main(String[] args) { ArrayList<Integer> al1 = new ArrayList<Integer>(); al1.add(1); ArrayList<String> al2 = new ArrayList<String>(); al2.add("hello"); //int型链表和string型链表,结果为true System.out.pr