`
顽石
  • 浏览: 164009 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

面向业务接口的业务事件交付

 
阅读更多

      在轻量流程引擎接口设计中提到触发业务事件需要调用事件的deliver方法来触发并交付业务事件,流程引擎最终会调用业务服务组件的事件处理方法,例如对买家确认收货事件,会调用收货组件的确认收货方法。采用这种显式交付业务事件的方式,开发人员需要new一个对应的业务事件对象,然后调用该事件的deliver。这种方式不是很友好,在没有采用流程引擎之前,开发人员直接调用收货组件接口来进行确认收货。采用流程引擎后,开发人员希望仍希望采用这种面向业务组件接口的编程方式,但流程引擎是采用事件驱动的,流程引擎根据事件来调用对应的业务服务组件,也就是不会让开发人员来直接调用业务服务组件。 因此为了沿用先前的调用方式,需要有一种机制来将完成业务方法调用到业务事件的转换(业务方法->业务事件),通过这种转换来达到隐式交付业务事件的目的。为了完成这种转换,需要增加一个间接层,这里采用代理模式(Proxy设计模式)来实现间接层,完成方法调用到业务事件的转换,更优雅的方式是直接使用spring aop。这里我们自己用Java动态代理而不是直接用AOP。

       在转换时,需要建立方法调用参数和业务事件属性之间的对应关系(映射关系),在技术上在采用annotation来注解方法,建立方法参数和事件属性之间的对应关系。

        先简要介绍下Java动态代理。

       Java动态代理

     代理模式是一种常用的设计模式,其目的是为了控制对某个真实对象的访问。代理对象和真实对象一般实现了相同的接口。客户端在调用代理对象的方法时,代理对象负责将调用委托给真实对象,在委托的前后,代理可以进行一些控制或预处理工作。

      Java动态代理的核心是java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口,动态代理是实现AOP的一种方式。注意此Proxy不是代理模式中的代理类,而是生成代理对象的工厂。客户端在调用代理对象时,需要先调用Proxy类的newProxyInstance静态方法生成代理对象实例,在调用该方法时,需要传入真实对象实现的接口和InvocationHandler的实现类对象,然后newProxyInstance会返回一个实现了这些接口的代理对象。由于是在JVM虚拟机运行过程中生成代理类,不需要事先定义代理类的类文件,因此叫动态代理。

      InvocationHandler是调用处理器接口。无论客户端调用代理对象的哪个接口方法,最终均会调用到invoke方法上,这是动态代理机制内部实现的。在该接口实现类的invoke方法中集中统一处理在代理对象上的方法调用,实现对真实对象的委托访问。 

   InvocationHandler接口的invoke方法签名如下:

   /* proxy就是Proxy类的newProxyInstance工厂方法返回的代理对象实例,method是客户端调用该代理对象的方法表示,args就是方法的参数。

  */     

  public Object invoke(Object proxy, Method method,Object[] args);
 

   Proxy类的newProxyInstance方法签名如下:

   /*loader为类装载器,用于加载动态生成的代理类、 interfaces为接口数组、

      h为 InvocationHandler接口实现。

      返回创建的代理对象实例。

   */
   static Object newProxyInstance(ClassLoader loader, Class[] interfaces,
    InvocationHandler h);

 

   BusinessEventAttr annotation

   BusinessEventAttr为业务事件annotation注解,作用于业务组件接口方法(前文中的南向接口)上,建立方法参数和事件属性之间的对应关系。建立对应关系后,就可从业务组件接口方法参数中提取事件属性。    下面是用于买家确认收货业务组件接口的注解:

    interface BuyerConfirmReceptionService{
       @BusinessEventAttr(businessKey="$inputScope[0]",

                                          roleId="$inputScope[1].id",eventType="buyerConfirmReceptionEvent")
       ConfirmReceptionResult confirm(Integer tradeId,RoleInfo roleInfo);
    }

    注解的属性通常是常量或表达式。

    上面的注解属性businessKey=”$inputScope[0]”,表示businessKey属性值是confirm方法的第一个输入参数tradeId(交易ID,通常交易ID和订单ID相同)。businessKey代表业务ID,业务ID和流程实例ID一一对应,对应关系可由流程引擎维护,此处之所以不用流程实例ID是为了避免业务组件和流程引擎耦合。

     roleId="$inputScope[1].id"表示角色id是confirm方法的第二个参数对象roleInfo的id属性;eventType为事件类型。

   BusinessEventAttr其他属性,如流程名称、是否同步事件等就不列出了。

    采用注解的方式表达接口方法中的事件信息后,南向接口的定义更为自由,其事件处理方法中的参数可以有多个,例如上面的confirm方法有两个参数。

     

    业务对象代理工厂类

     客户端使用业务服务代理工厂类来生成业务服务代理。为了方便客户端编程,该代理工厂类对java动态代理api进行了封装,简化客户端调用。该工厂类定义如下:

     public class BusinessServiceProxyFactory {
     @SuppressWarnings("unchecked")
     public static <T> T getProxy(Class<T> intf) {
         return (T) Proxy.newProxyInstance(BusinessServiceProxyFactory.class.getClassLoader(),new Class[]{intf},
                    new InvocationHandler() {
                        public Object invoke(Object proxy, Method method,
                                             Object[] args) throws Throwable {

                            //获得注解实例
                            BusinessEventAttr eventAttr = method.getAnnotation(BusinessEventAttr.class);
                            //完成业务方法调用到业务事件的转换,根据eventAttr和args调用populateEvent拼装                        //业务事件,完成方法调用到业务事件的转换。
                            BusinessEvent bzEvent = populateEvent(eventAttr,args);
                            //获取流程引擎
                            FlowEngine flowEngine =  FlowServicesLocator.getFlowEngine();
                           /*调用startFlow驱动流程,提交业务事件。流程引擎会根据bzEvent中的业务ID找到对应的流程实例ID,然后根据该流程实例所处的当前节点和事件类型,调用该节点上配置的南向接口上的事件

                              处理方法(即业务服务层的业务服务组件方法),调用完成后,进行流程流转,返回调用

                              结果。
                            */
                            return flowEngine.startFlow(bzEvent);
                        } // end invoke
                    }); //end new InvocationHandler()
        } 
   } 

        BusinessServiceProxyFactory类只有一个方法getProxy(Class<T> intf),传入业务服务组件接口,返回

   一个实现了该接口的动态代理实例,对返回采用了范型类型,这样客户端调用时不需要cast。getProxy其实只包含一行代码,就是调用Proxy.newProxyInstance方法,newProxyInstance方法中的 InvocationHandler的实例为匿名类。

       这个BusinessServiceProxyFactory也可封装为spring 中的factorybean,它返回业务服务实例(是一个代理)。

        在invoke方法中完成业务方法调用到业务事件的转换,然后启动流程(流程启动后,会调用事件处理器,最后进行流程流转)。

        在轻量流程引擎接口设计中提到的BusinessEvent需要将BusinessDataDto businessData属性改为    Object args[ ];

     

      客户端调用

    以某交易流程中的买家确认收货为例说明客户端的调用。买家签收物流送来的宝贝后,打开该订单web页面,点击页面中的"确认收货"按钮。系统将调用Action控制类的execute方法或doXXX方法,在execute该方法中调用买家确认收货服务的confirm方法,execute方法示例如下:

    //todo进行一些权限验证或数据组装工作

    ...

    //调用业务服务代理工厂的getProxy工厂方法得到买家确认收货服务实例,该实例是一个动态产生的代理   

    BuyerConfirmReceptionService    confirmService =  

                    BusinessServiceProxyFactory.getProxy(BuyerConfirmReceptionService.class);

 

     /*和未采用流程引擎之前一样,仍调用BuyerConfirmReceptionService业务接口的confirm方法,  confirmService不真正指向业务服务层的确认收货组件,它是一个代理,作为面具来伪装,让开发人员觉得是调用确认收货服务。对confirm方法的调用会转到上面的 InvocationHandler匿名类的invoke方法中,从而将confirm方法调用转换为确认收货的业务事件。

       在返回的result结果中包含流程实例的最新流转状态,也可提供一个接口来专门查询流程实例状态。

     */

    ConfirmReceptionResult  result = confirmService.confirm(tradeId,roleInfo);

    ...

    

    

     如上节业务对象代理工厂中所述,在InvocationHandler匿名类的invoke方法中调用flowEngine.startFlow时,流程引擎将会调用业务逻辑层的买家确认收货组件的confirm方法(流程定义文件中的事件处理器方法)。业务服务层的买家确认收货组件实现BuyerConfirmReceptionService接口,在该业务服务层组件的confirm方法中,开发人员只需要考虑如何处理买家确认收货逻辑,不需要关心流程流转,也不需要调用流程引擎api;在action类中也不需考虑流程流转和调用流程引擎api,也就是流程引擎api不会侵入其他层的代码中,实现了业务逻辑层和流程层的完美解藕和隔离。

    

    流程引擎和流程定义文件

     采用DSL来定义流程(包含节点定义、事件处理器、流转条件),流程DSL对流程api进行封装(创建流程实例api、设置修改流程变量api等)。

     流程定义文件除了包含节点定义、事件处理器、流转条件外,还可以在其中定义流程脚本(使用Java或groovy动态语言编写的代码片段):修改或设置流程变量的脚本、action脚本、流出操作、流入操作等。

     通过流程DSL和这些流程脚本,把流程相关的逻辑全部封装在流程层,保证了这些流程逻辑不会侵入到业务服务层,业务服务层也就不需要调用这些流程api了。例如在开始节点中处理下单事件的业务组件(生成订单组件)不需要调用流程api来创建流程实例,创建流程实例是由流程层负责调用流程api来创建的,生成订单的组件不关心流程实例的创建。

     流程引擎提供了对多种流程模式的支持,如and-join模式。 

 

    

         

       

 

  

分享到:
评论
1 楼 maetrive 2016-08-02  
很不错!

相关推荐

    springcloud微服务

    - 面向服务:面向服务是说每个服务都要对外暴露服务接口API。并不关心服务的技术实现,做到与平台和语言无关,也不限定用什么技术实现,只要提供Rest的接口即可。 - 自治:自治是说服务间互相独立,互不干扰 - 团队...

    GMTC北京 2017年全球前端技术大会PPT合集(46份).zip

    GMTC北京 2017年全球前端技术大会PPT合集(46份)。 移动开发的未来-来自一个移动开发者的自白 移动Web的现在与未来 移动分析助力App精细化运营 一站式短视频技术架构的新解读 ...面向业务的界面解决方案 等等文档

    系统架构师备考知识点梳理

    JTAG接口:用于CPU调试的常用接口 RUP(统一软件开发过程),用例驱动 初始:建立业务模型,确定项目边界 细化:建立完善架构 构建:开发构建,集成产品,详细测试 交付:确保可用 ...... 论文题: 项目涉及到的技术...

    移动互联网复习题.doc

    移动云计算: 指通过移动网络以按需、易扩展的方式获取所需的基础设施、平台、软件的一种 IT 资源或服务的交付与使用模式。 体系结构: 指计算机或计算机系统的组件的组织和集成方式。 SOA: 即面向服务的体系结构...

    1移动互联网复习题.doc

    移动云计算: 指通过移动网络以按需、易扩展的方式获取所需的基础设施、平台、软件的一种 IT 资源或服务的交付与使用模式。 体系结构: 指计算机或计算机系统的组件的组织和集成方式。 SOA: 即面向服务的体系结构...

    2021 QECon全球软件质量&效能大会(上海站)PPT汇总(57份).zip

    九、业务价值交付 大数据测试-数据测试平台的业务赋能 App端到端用户体验分析与实践 十、云原生质量 混沌工程:云原生可靠性治理的创新 腾讯互娱营销技术平台的云原生改造实践之路 一体化开发云研效平台落地实践 ...

    软件开发类投标项目全套解决方案模板

    4.1.1.3.3 面向服务的SOA接口集成 35 4.1.1.3.4 高并发处理机制 36 4.1.1.3.5 高效的内存数据库 36 4.1.1.3.6 兼容多种集成模式 36 4.1.1.3.7 开放式的框架设计 36 4.1.1.3.8 数据库选型 36 4.1.1.4 应用工具 ...

    客客威客系统KPPW v2.5 GBK Beta.zip

    且针对现有的服务和作品的业务功能进行了进一步细化的深入,满足了大部分的创意型产品的买卖交易。 五、用户经验权限体系改造更体贴 新版本重构了用户经验权限体系,针对威客应用的贴切需求,将雇主信用和威客能力...

    新开普-中小学管理平台规划建设方案(195页).docx

    基于SOA的体系架构和面向师生的一体化服务,通过服务之间定义良好的接口定义和服务注册把不同功能单元(成为服务)联系起来,使得构建在各种系统中的服务可以以一种统一和通用的方式进行交互。 3、资源共享 通过信息...

    软件工程知识点

    通过系统的外部事件、内部状态为基本元素来描绘系统的工作流程,这种建模方式比较适合于描述一些依赖于外部事件驱动的实时系统。 5.需求有效性验证 需求有效性验证是指对已经产生的需求结论所要进行的检查与评价。...

    虚拟化--docker.ctb

    容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。 Docker 从 17.03 版本之后分为 CE(Community Edition: 社区版) 和 EE(Enterprise Edition: 企业版),...

    【卷一/共两卷】AJAX实战pdf高清版90M

    1.2.2 服务器交付的是数据而不是内容 1.2.3 用户交互变得流畅而连续 1.2.4 有纪律的严肃编程 1.3 真实世界中的Ajax富客户端 1.3.1 现状 1.3.2 Google Maps 1.4 Ajax的替代方案 1.4.1基于Macromedia Flash的方案 ...

    常见服务器储存类型.pptx

    NAS则充分利用系统原有的网络接口,对存储的访问是通过通用网络接口,访问通过高层接口实现,同时设备可专注与存储的管理,优点是系统简单、兼容现有系统、扩容方便,缺点则是效率相对比较低。 常见服务器储存类型...

    软件设计规范

    (迭代流程)基于固定寻址的变量,经过寻址接口,可以处理任意数据,从而把迭代流程变成了一般流程。CPU的基本过程,产生了指令和数据,指令天生具有子程序的基因(一般流程),数据天生具有数据结构(寻址能力)的...

    PDM产品配置管理的研究

    本文主要研究了客户需求的配置管理,分析了企业配置中心的功能,用面向对象的方法建立配置中心管理模型,主要包括产品选项管理模型和产品配置模型。 一、产品配置管理的概念 按照国际标准ISO10007的定义,配置是指对...

Global site tag (gtag.js) - Google Analytics