使用 ABAP Messaging Channel 实现多用户会话间的消息发布和订阅

文摘   2024-10-15 07:01   四川  

笔者之前的系列文章,详细介绍了使用 ABAP Push Channel(简称 APC)来开发 TCP Socket 和 Web Socket 服务器端和客户端的实现步骤。

ABAP Push Channels(APC)是一种可以实现与服务器的全双工(full-duplex)通信技术。名称里的 Push,强调了即使客户端并未向服务器端发起数据请求,服务器也能够通过该技术,将消息主动推送到客户端。

在早期 ABAP 不支持 APC 技术的时代,作为客户端的浏览器,如果想获取来自服务器端的最新数据,比如消息,通知,提示,警报等,就必须以一个时间间隔,不停地向服务器端发起 HTTP 轮询(Poll),即使服务器没有任何新的数据产生。

这种低效的轮询会导致大量不必要的请求,浪费带宽和服务器资源。

ABAP 7.40 SP5 正式发布的 APC 技术,解决了 HTTP 轮询机制带来的弊端。APC 能够在服务器有新数据就绪时,立即推送通知到客户端,从而避免了频繁的轮询请求,减轻了服务器和网络的负担,真正实现了服务器和客户端的实时双向通讯。

笔者之前的 ABAP 开发教程,曾经详细介绍过 ABAP 编程环境的 Internal Session,ABAP Session 和 User Session 三个概念的辨析。比如一个 ABAP Session 内可以通过调用 ABAP 程序,执行关键字 SUBMIT 和 CALL TRANSACTION 等方式,开启新的 Internal Session.

同一 ABAP Session 之内的多个 Internal Sessions 之间,可以通过 ABAP Memory 来共享和交换数据,如下图所示。

ABAP Messaging Channels (AMC) 是 ABAP 程序之间,使用`消息`进行通信的另一种方法。任何 ABAP 程序之间都可以通过 AMC 交换消息,包括不同 User Sessions 和 ABAP 应用程序服务器之间的通信。

ABAP Messaging Channel 采用了大家熟知的设计模式中的发布/订阅者(Publisher & Subscriber)模式,来实现 ABAP 程序间的消息交换。

参与消息交互的双方,在特定的 Communication Channel 上,通过同步或者异步的方式发布和订阅消息。

下面是一张简单的示意图。

User Session P1 作为消息发布者,将消息发布到 ABAP Message Channel Framework 管理的 Channel X 中去。另外三个 User Session S1,S2 和 Sn 订阅了这个 Channel X,因此它们能够从 Channel X 接收到消息。

随后的某个时间点,Sn 取消了消息订阅。从这一时刻起,它不会再收到来自 Channel X 的消息转发。

下面介绍基于 ABAP Message Channel 的消息发布者和订阅者的详细开发步骤。

事务码 SE80 的右键菜单,选择创建一个新的 ABAP Messaging Channel:

给这个新建的 ABAP Messaging Channel 应用,维护名称和描述信息。下面是新建 AMC 应用需要维护的关键属性的详细解释。

一个 AMC 应用可以维护多个 Channel,本例 Channel 名称为 /ping.

AMC 应用的名称和 Channel 名称这一对字段,唯一标识一个 ABAP Message Channel,可以看成通过 AMC 机制进行发布和订阅消息的主键。

Message Type ID 即在 Channel 通道里流动消息的数据类型,本例选择 TEXT 即文本类型。

Activity Scope 即 Message Channel 的作用范围,这里选择 Client 即消息的发送者和接受者必须在 ABAP 应用服务器的同一个 Client 上。选择 System 则支持 Cross Client 即跨 Client 的消息交换。

Authorized Program 即能够使用当前 AMC 应用的白名单列表,如上图图例5 所示。

只有 ZDEMO_SEND_AMC 才有权限,往这个 Message Channel 里发送消息。同理,只有 ZDEMO_RECEIVE_AMC 才有权限从 Message Channel 接收消息。其他任何没有声明在这个白名单上的 ABAP 程序,试图通过该 Message Channel 发布或者订阅消息时,会遇到运行时错误。

使用 ABAP 发布 AMC 消息

实现上图白名单里声明的 ZDEMO_SEND_AMC 程序。

简单的 17 行代码:

REPORT zdemo_send_amc.
DATA text_message TYPE string VALUE `I am a text message`.
DATA session_id TYPE amc_consumer_session_id.
cl_demo_input=>new(
)->add_field( EXPORTING text = 'Text message'
CHANGING field = text_message
)->request( ).
CAST if_amc_message_producer_text(
cl_amc_channel_manager=>create_message_producer_by_id(
i_consumer_session_id = session_id
i_communication_type = cl_amc_channel_manager=>co_comm_type_synchronous
i_application_id = 'ZAMC_SIMPLE_TEST'
i_channel_id = '/ping' )
)->send( i_message = text_message ).

这个简单的 ABAP 程序,定义了一个输入字段 text_message,作为待发布到 Message Channel 中的消息内容。因为我们之前创建 AMC 时,Message Type 指定为 Text,所以这里的输入字段的 ABAP 类型选择为 string.

通过 cl_amc_channel_message 的静态方法 create_message_producer_by_id, 创建一个新的消息发布者。Communication Type 选择为同步方式,当然 AMC 也支持异步消息发布。

该静态方法还需要传入 AMC 应用名称和 Channel 名称,告知创建好的 Producer 实例,其发布消息的目的地所在。

静态方法返回的类型为 IF_AMC_MESSAGE_PRODUCER,我们使用 CAST 关键字,将其类型转换成更具体的 IF_AMC_MESSAGE_PRODUCER_TEXT, 以便进行 TEXT 类型消息的发布。

最后调用 IF_AMC_MESSAGE_PRODUCER_TEXT 的 send 方法,将消息发布到指定的 Message Channel 中去。

使用 ABAP 接收 AMC 消息

实现 AMC 应用创建时,白名单里维护的 ZDEMO_RECEIVE_AMC 程序。

试图从 Message Channel 里读取其他发布者写入消息的订阅者,需要实现 ABAP 接口 IF_AMC_MESSAGE_RECEIVER_TEXT. 这个接口提供了一个 receive 方法。当订阅的 ABAP Message Channel 有消息到达时,receive 方法会自动触发。

在本例的接收方实现里,receive 方法触发时,将通过输入参数 i_message 传递进来的消息文本内容,存储到类实例的 text_message 成员变量里。 

使用 ABAP 代码,订阅 ABAP Message Channel 发布消息的三大要点,如下图图例所示。

1. 新建一个实现了 IF_AMC_MESSAGE_RECEIVER_TEXT 接口的类实例。该类的成员变量 text_message 用来存储 Message Channel 里订阅的消息的文本内容。该类实例作为消息的订阅者。

2. 使用 cl_amc_channel_manager 的 create_message_consumer 静态方法,创建一个 Message Channel 订阅者。需要订阅的具体 Channel 信息,通过指定的 AMC 名称和 Channel 名称来区分。

该静态方法返回一个 consumer 实例,调用该实例的 start_message_delivery 方法,把上一步骤创建的订阅者实例,传递给该方法的输入参数 i_receiver. 至此消息订阅就完成了。

3. 调用 ABAP 关键字 WAIT FOR MESSAGING CHANNELS UNTIL XXX UP TO YYY, 等待订阅的 ABAP Message Channel 中有消息发布进来。

YYY 是指定 WAIT 语句的超时时间,而 XXX 处需要指定一个逻辑表达式,本例使用的是 receiver->text_message IS NOT INITIAL

如果逻辑表达式的值为 FALSE, 该 ABAP 程序将一直处于 WAIT 状态。

当订阅的 Message Channel 上有其他 ABAP 程序发布消息时,订阅者实例的 receive 方法会被 AMC 框架触发,消息内容会写入实例的成员方法 text_message 内。这会导致 receiver->text_message IS NOT INITIAL 表达式的值变为 TRUE,因此 WAIT 语句完成其执行,将 sy-subrc 设置为 0,然后 ABAP 程序从 WAIT 语句的下一行继续执行。

我们对迄今为止编写的发布者 & 订阅者场景做一个简单的测试。

依次开启两个 SAPGUI 窗口登录系统,这样我们就有了两个不同的 User Sessions.

在第一个窗口里执行 ZDEMO_RECEIVE_AMC,弹出对话框,指定 WAIT 操作的超时时间,默认为 60 秒。点击 Enter 按钮触发程序的执行。

此时我们可以观察到,该程序进入了等待状态,等待订阅的 Message Channel 上消息的到来。

在第二个 SAPGUI 窗口里,执行 ZDEMO_SEND_AMC. 在输入字段里随便维护一些文本。点击 Enter 按钮之后,这些文本将会被写入 ABAP Message Channel.

点击 Enter 按钮之后,第一个 SAPGUI 窗口里的 ZDEMO_RECEIVE_AMC 程序,从 WAIT 状态中被唤醒,打印出来自第一个 SAPGUI 窗口发布的消息内容。

总结

本文演示了通过 ABAP Messaging Channel 技术,在不同的 User Sessions 里通过消息发布和订阅的方式,进行数据交换的开发步骤。

在笔者另一篇文章 我用 ABAP 做过的那些无聊的事情 里介绍过一个 Function Module TH_POPUP, 可以通过点对点的方式,给不同 User Session 的其他用户,以弹出框的方式发送文本消息。

只需要通过该 Function Module 的 USER 输入参数,指定期望接收到该弹出框的用户名,以及 MESSAGE 参数来维护弹出的文本内容。

执行 Function Module 之后,另一个 User Session 的 SAPGUI 窗口,就会弹出下面这种对话框。

当然,同这种最简陋的对话弹出框相比,ABAP Messaging Channel 不仅支持包括 Text,自定义结构和二进制流的各种消息格式,也支持同步和异步两种消息发布和订阅方式,功能比 TH_POPUP 要强太多了。

汪子熙
企业管理软件领域开发专家
 最新文章