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

      在轻量流程引擎接口设计中提到触发业务事件需要调用事件的deliver方法来触发并交付业务事件,流程引擎最终会调用业务服务组件的事件处理方法,例如对买家确认收货事件,会调用收货组件的确认收货方法。采用这种显式交付业务事件的方式,开发人员需要new一个对应的业务事件对象,然后调用该事件的deliver。这种方式不是很友好,在没有采用流程引擎之前,开发人员直接调用收货组件接口来进行确认收货。采用流程引擎后,开发人员希望仍希望采用这种面向业务组件接口的编程方式,但流程引擎是采用事件驱动的,流程引擎根据事件来调用对应的业务服务组件,也就是不会让开发人员来直接调用业务服务组件。 因此为了沿用先前的调用方式,需要有一种机制来将完成业务方法调用到业务事件的转换(业务方法->业务事件),通过这种转换来达到隐式交付业务事件的目的。为了完成这种转换,需要增加一个间接层,这里采用代理模式(Proxy设计模式)来实现间接层,完成方法调用到业务事件的转换。转换时,需要建立方法调用参数和业务事件属性之间的对应关系(映射关系),在技术上在采用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模式。 

 

    

         

       

 

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值