Apache OFbiz service engine 源码解读

简介:

上一篇看完了ofbiz entity engine,这篇再来过一下ofbiz的service engine。service engine层在设计模式的使用上跟entity engine有些类似,最典型的就是“业务代表”模式。service engine跟entity engine是紧密相关的,大部分的业务系统所要执行的服务都是跟关系数据库相关的。

service engine对于服务编写的方式有着非常广泛的“自由”,你可以选择它内置引擎支持的任何一种方式来编写服务。同时对于eca的支持对于事务的支持以及对于权限的支持都非常的完善。

Service执行方式的抽象——LocalDispatcher

该接口提供了ofbiz中service调度执行器基本协议方法的定义,包括:

  • 同步执行
  • 异步执行(其实也是基于job加多线程)
  • 定时执行(基于job以及job pool)
  • 添加【提交/回滚事务时执行的】service
  • 一些关键“传输对象”的访问器
dispatcher相关的类继承关系:

备注:此接口是service engine中比较关键的“业务代表”接口,其取名为LocalDispatcher是为了以示跟后面提及的RemoteDispatcher(用于支持RMI的remoteEngine)进行区分。

LocalDispatcher的抽象实现——GenericAbstractDispatcher

GenericAbstractDispatcher提供了对LocalDispatcher中定义的部分方法的实现(主要涉及到定时执行、事务相关的几个接口方法)。它内部依赖几个关键对象,是在其子类中注入的,这几个关键对象名:
  • ctx:serviceengine的上下文对象
  • dispatcher:ServiceDispatcher的实例,是真正的服务执行者

LocalDispatcher的标准通用实现——GenericDispatcher

上文提到GenericAbstractDispatcher中有几个关键对象是在其子类中被初始化的。其实,就是在GenericDispatcher中(GenericDispatcher是GenericAbstractDispatcher的唯一子类)。关键对象的初始化位于init方法中,而init方法又是被GenericDispatcher的构造方法调用。此处需要注意的是,GenericDispatcher的两个构造器(包含无参构造器)都被设置为protected。也就是说你无法在外部通过调用无参构造器来初始化GenericDispatcher的实例(如果允许这种行为,那么其父类GenericAbstractDispatcher的那两个关键对象将不能保证被实例化)。那么GenericDispatcher是在哪里被实例化的?这需要谈到GenericDispatcher提供的几个公有静态方法:

如果你关注一下他们的返回值类型,你就能知道为什么之前提到LocalDispatcher是“业务代表”对象了。它将成为应用程序其他组件与service engine打交道的主要代理人(就跟entity engine层的Delegator接口一样),因此在这些方法中实例化的GenericDispatcher对象都向上转型为了LocalDispatcher。

因为它是关键对象创建它的代价比较大,考虑到性能因素GenericDispatcher为所有的dispatcher对象提供缓存。另外一个需要关注的是:GenericDispatcher大量依赖ServiceDispatcher(从其构造器需要注入ServiceDispatcher的实例就可以看出来)。或者你可以看到下面实现的所有的runXXX接口方法基本都是依赖ServiceDispatcher去执行的。

真正的服务调度器——ServiceDispatcher

上面说到其实之前的Dispatcher都不是服务的真正执行者。服务的真正执行者是:ServiceDispatcher。千万不要被上面的那些XXXDispatcher后缀的类所欺骗,它们只不过是官方代表而已。ServiceDispatcher并没有继承以及实现任何东西,但是它拥有一些强大的部件:
protected Delegator delegator = null;
protected GenericEngineFactory factory = null;
protected Authorization authz = null;
protected Security security = null;
protected Map<String, DispatchContext> localContext = null;
protected Map<String, List<GenericServiceCallback>> callbacks = null;
protected JobManager jm = null;
protected JmsListenerFactory jlf = null;

ServiceDispatcher的构造方式跟GenericDispatcher类似。都是将构造器设置为protected,对外通过静态方法获得实例,同时拥有对它自身实例对象的缓存。

其实,在业务系统中大部分的操作都是跟数据库打交道,而Delegator又是entity层的业务代表,所以ServiceDispatcher非常依赖于Delegator。

而服务最终到底是怎样被执行的呢?最终每个服务都是依赖于符合它执行条件的执行引擎来执行的!(关于各种引擎,后面会介绍)。上面的关键部件里有个GenericEngineFactory的实例,它用于创建合适的执行引擎。

下面简述一个通用服务的执行过程:
  • 定义或者初始化一堆执行过程中需要用到的参数
  • 检测服务是否带有锁标识:如果有,则创建一个锁,并获得锁对象
  • 创建一个上下文对象,如果服务的执行过程中需要携带参数,将参数都加入上下文对象
  • 检测上下文对象的Locale
  • 对当前service进行log
  • 检测当前服务是否定义有event,如果有,一次全部取出
  • 取得合适的执行引擎
  • 更新上下文对象中,IN 类型参数的默认值
  • 如果该服务被定义为在事务中执行,则启用事务
  • 依次执行“global-rollback”、“global-commit”、“auth”相关event的action,并带出执行结果
  • 检查pre-auth的执行结果是否为失败或错误
  • 检查上下文对象中键值对参数的权限,同时设置【key为"userLogin"】的value为【用户信息对象】
  • 检查userLogin对应的用户信息对象,如果权限验证失败,则抛出异常
  • 执行“in-validate”预检查事件,同时带出对action的执行结果
  • 检查是否有失败或错误产生
  • 检查所有上下文参数中输入参数是否合法
  • 执行“invoke”事件,同时带出action的执行结果
  • 检查是否有失败或错误产生
  • 通过服务执行引擎来执行服务并取得执行结果
  • 通过服务执行引擎发送服务回调,如果执行结果不为空,则将其加入result结果集
  • 检查是否有错误或失败产生
  • 错误处理
  • 重新构建一个eca的上下文对象
  • 执行“out-validate”事件,同时带出结果集
  • 验证结果集中得输出参数是否合法
  • 执行“commit”事件,同时带出结果集
  • 检测结果集是否含有失败或者错误
  • 执行“global-commit-post-run”事件,同时带出结果
  • 进入异常处理部分:通过服务引擎,发送带异常的回调,回滚事务
  • 进入finally部分:如果有错误,回滚事务,否则提交事务,调用notification,这里的事件是由结果集来决定的
  • 进入外层finally部分:如果锁没有被释放,则释放锁。恢复父级事务
  • 执行“return”事件,同时带出结果集
  • 返回结果集,方法结束

服务调度的上下文——DispatchContext

在之前的不少地方其实已经用到过DispatchContext,它为服务的执行提供上下文(主要是一些关键对象及参数)。它主要提供了一堆get访问器,以及一些辅助方法,比如加载本地servicemap以及globalservice map等。

异步请求器——GenericRequester


该接口定义了两个回调方法:一个用于接受一个map(通常是上面serviceDispatcher的执行结果),另一个接受一个Throwable对象。它主要的用途就是在调用runAsync方法的时候(异步执行服务),将该接口的实现者作为参数传入(可以理解为回调对象)。主要的过程是这样的:

首先,ServiceDispatcher实例调用runAsync方法,在该方法接受一个GenericRequester类型的参数,在方法内部真正的执行引擎会调用它自己的runAsync方法,该接口的实例继续向前传递作为参数。而执行引擎对该runAsync的实现主要在GenericAsyncEngine中,实现的方式是这样的:它最终会用GenericRequester的实例以及一些其他对象创建一个我们下面会提到的GenericServiceJob的实例。最终所谓的Async只不过是转化为了其他线程去独立执行一个Job而已,在该job的exec方法中,dispatcher会同步执行runSync,然后得到结果,提供给GenericRequester调用(上面截图中得方法)。因此这里所谓的runAsync其实是在另外一个独立的线程上去执行runSync,然后将结果传递给回调对象,执行回调方法而已。

Service中的任务——Job

job在serviceengine中有非常重要的作用,除了用于支持定时执行外,所谓的异步执行也是通过job来实现的。

上图为ofbizservice engine中的Job继承链。其中,Job接口定义了在serviceengine中作为一个Job应该遵守的“协议”。协议列表如下:

其中有两个关键方法:
  • exec: 定义如何执行一个job
  • queue: 标识一个job是否“已压入队列”

用于执行服务的抽象Job——AbstractJob