服务引擎的理解

      服务是定义为一段独立的逻辑程序,当多个服务组合在一起时就可以完成不同类型的业务需求。Ofbiz服务能调用其他服务定义,将多个小的服务串联起来实现一个大的任务。服务通过服务定义文件来定义并指派给具体的服务引擎。每个服务引擎通过适当方式来调用服务定义。在Ofbiz服务引擎中,服务需要使用Map传入参数,结果同样从Map中返回。

常见的几种服务类型

1.Interface服务引擎

     interface 服务引擎实现在服务定义时可以共享相同的参数。一个接口服务不能被单独调用,服务功能是在实现服务接口的其他服务定义中实现的。每个接口服务都需要用interface 引擎来定义。

 2.ECA(Event Condition Action)

     ECA类似一个触发器,当一个服务被调用时,会检查是否为这个事件定义ECAs ,在验证、检验、事件实际调用、输出参数校验、事务提交或者服务返回之前包含进来。每个条件都会被验证,如果全部返回为真,定义的动作将会被执行。一个动作就是一个服务,服务的参数必须是已经存在于服务的上下文中。

每个ECA可以定义的条件数或者动作数没有限制。(用ServiceEcaRule的静态方法来调用)

3.服务组

      服务组是由多个服务组成的服务集合,使用组服务定义文件来定义一个组服务,当这个组服务被调用时,组中定义的所有服务都会被调用。(ServiceGroupEngine.java)

      组的定义比较简单,包含一个拥有多个 service 元素的 group 元素。group 元素包含一个 name 属性和一个 mode 属性, 其中mode  用来定义服务怎么执行。service  元类似于 ECA  中的action元素,不同之处在于 result-to-context 属性的默认值。

4.路由服务

      路由服务使用路由服务引擎定义。当一个路由服务被调用时,所有定义的 ECA 会在适当事件中被运行。路由服务通过利用ECA服务选项可以路由( 'route') 到其他服务。(RouteEngine.java)

5.HTTP服务

      HTTP服务是调用定义在其他系统上远程服务的一种方法。远程定义和本地定义是一致的,但其引擎应该是http。location 应该是httpService 事件在远程系统上运行的完全URL,方法是远程系统上被调用运行的服务名。在远程系统上的服务必须将export属性设为true允许远程调用。

      HTTP 服务本质就是同步的。(HttpEngine.java)

6.异步服务

      异步服务就是job scheduler异步调用的工作/服务。它包含池化的线程和几个请求线程。thread-pool 标签用来配置每个线程怎么操作。

OFBizservices调用机制

Services的调用是从请求开始的,ControlServlet 就是所有请求过程的核心。当收到一个请求时,servlet 首先会设置系统环境信息,这里会将LocalDispatcher与Delegator设置到HttpServletRequest变量中去。View控制器Controller通过调用LocalDispatcher(实现类GenericDispatcher)将请求转发到ServiceDispatcher上,通过ServiceDispatcher来调用合适的服务引擎GenericEngine。服务引擎调用相应的实体引擎(Delegator的实现类GenericDelegator)来完成业务逻辑。事务管理是在ServiceDispatcher中完成的(异步调用最终也是在Job线程中调用ServiceDispatcher的同步方法)。

View控制器controller中如下调用服务:

LocalDispatcher dispatcher = dctx.getDispatcher();
Map<String, Object> result = dispatcher.runSync(getServiceName(), getContext());

服务是声明在service.xml文件中的,声明格式如下:

<service name="createSurveyReport4Receipt" engine="java"确location="org.sample.warehouse.shipment.ShipmentReceiptServices" invoke="createSurveyReport4Receipt">

        <description>Create SurveyReport for ShipmentReceipt</description>

        <attribute name="receiptId" type="String" mode="INOUT" optional="false"/>

        <attribute name="receiptTypeId" type="String" mode="IN" optional="true"/>

        <attribute name="statusId" type="String" mode="IN" optional="true"/>

        <attribute name="inspectId" type="String" mode="OUT" optional="true"/>

</service>

   LocalDispatcher是本地调度器,实现服务的同步异步调度和定时任务的调度。服务最终是通过ServiceDispather分配到适当的服务引擎,最终交由GenericEngine来完成。每个实体引擎代理都有一个具体的 ServiceDispatcher实例(一个ServiceDispatcher实例对应一个实体引擎代理)。每个LocalDispatcher 都是唯一命名并包含自己的一些服务定义。

      在ServiceDispatcher中,通过调用ServiceEcaUtil.evalRules()方法来执行ECA检验,并通过调用TransactionUtil方法来完成事务处理。

      在请求处理过程中,如果遇到service的event,那么EventHandler会使用LocalDispatcher执行service。

同步调用

通过dispatcher调用runSync方法(即调用GenericDispatcher的runSync方法,最后转为ServiceDispatcher去完成任务- 调用dispatcher->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实例。
}

其中,dispatcher实际是ServiceDispatcher对象。ServiceDispatcher的runSync方法有三百多行,比较复杂,但最终调用service的是GenericEngine。

GenericEngine engine = this.getGenericEngine(modelService.engineName);
    ……
    
    Map<String, Object> invokeResult = engine.runSync(localName, modelService, context); //engine是服务的实现

GenericEngine是在其工厂类GenericEngineFactory获取的。从配置文件serviceengine.xml文件中获取相应的engine子类,如java的org.ofbiz.service.engine.StandardJavaEngine、bsh的是org.ofbiz.service.engine.BeanShellEngine。
不同的Engine实现的方式不一样。Java的StandardJavaEnignerunSync方法采用的是反射来执行相应的方法,如下:

Class<?> c = cl.loadClass(this.getLocation(modelService));

Method m = c.getMethod(modelService.invoke, DispatchContext.class, Map.class);

if (Modifier.isStatic(m.getModifiers())) {

    result = m.invoke(null, dctx, context);

} else {

    result = m.invoke(c.newInstance(), dctx, context);

}

一个标准Java服务实现类代码类似如下:

public class  xxxxx {

     public static Map doxxx(DispatchContext dctx, Map context) {

         GenericDelegator delegator = (GenericDelegator)dctx.getDelegator();

          //从context中取出参数

          Object param = context.get(…);

          //调用实体引擎代理执行数据库业务操作。

         delegator…..();

         //结果保存在result中.

         Map results = ServiceUtil.returnSuccess();   

         ….

         return results;

    }

}

这样在ServiceDispatcher中执行engine.runSync(localName, modelService, context);最终通过具体的服务引擎实现来调用具体的业务逻辑实现。

异步调用

      实现异步的原理就是启动一个线程来执行相应的业务逻辑,原方法直接返回,从而实现异步。具体实现可以根据实际情况而定,比如将业务逻辑封装成一个任务,再将此任务放到一个任务链中。最终由线程池选择任务进行执行。具体来查看GenericAsyncEngine的runAsync方法就会发现Ofbiz是通过生成一个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);
}

OFBizJob的运行机制

     OFBiz执行后台任务的类在org.ofbiz.service.job中。JobPoller和JobInvoker是其中主要的两个类,一个负责查询可以执行的Job,另一个执行Job任务。

在Ofbiz中基本上服务都是以下方式来运行的。

public void schedule(String jobName, String poolName, String serviceName, Map<String, ? extends Object> context, long startTime, int frequency, int interval, int count, long endTime, int maxRetry) throws GenericServiceException {

        Transaction suspendedTransaction = null;

        try {

            boolean beganTransaction = false;

            suspendedTransaction = TransactionUtil.suspend();

            try {

                beganTransaction = TransactionUtil.begin();

                try {

                    getJobManager().schedule(jobName, poolName, serviceName, context, startTime, frequency, interval, count, endTime, maxRetry);

                    if (Debug.verboseOn()) {

                        Debug.logVerbose("[LocalDispatcher.schedule] : Current time : " + (new Date()).getTime(), module);

                        Debug.logVerbose("[LocalDispatcher.schedule] : Runtime      : " + startTime, module);

                        Debug.logVerbose("[LocalDispatcher.schedule] : Frequency    : " + frequency, module);

                        Debug.logVerbose("[LocalDispatcher.schedule] : Interval     : " + interval, module);

                        Debug.logVerbose("[LocalDispatcher.schedule] : Count        : " + count, module);

                        Debug.logVerbose("[LocalDispatcher.schedule] : EndTime      : " + endTime, module);

                        Debug.logVerbose("[LocalDispatcher.schedule] : MazRetry     : " + maxRetry, module);

                    }

                } catch (JobManagerException jme) {

                    throw new GenericServiceException(jme.getMessage(), jme);

                }

            } catch (Exception e) {

                String errMsg = "General error while scheduling job";

                Debug.logError(e, errMsg, module);

                try {

                    TransactionUtil.rollback(beganTransaction, errMsg, e);

                } catch (GenericTransactionException gte1) {

                    Debug.logError(gte1, "Unable to rollback transaction", module);

                }

            } finally {

                try {

                    TransactionUtil.commit(beganTransaction);

                } catch (GenericTransactionException gte2) {

                    Debug.logError(gte2, "Unable to commit scheduled job", module);

                }

            }

        } catch (GenericTransactionException gte) {

            Debug.logError(gte, "Error suspending transaction while scheduling job", module);

        } finally {

            if (suspendedTransaction != null) {

                try {

                    TransactionUtil.resume(suspendedTransaction);

                } catch (GenericTransactionException gte3) {

                    Debug.logError(gte3, "Error resuming suspended transaction after scheduling job", module);

                }

            }

        }

    }

原文地址:https://www.cnblogs.com/jevo/p/2960489.html