【AICon】探索RAG 技术在实际应用中遇到的挑战及应对策略!AICon精华内容已上线73%>>> 了解详情
写点什么

PHP 开发者的 BlazeDS 和 JMS 指南,第二部分

  • 2010-07-19
  • 本文字数:6350 字

    阅读完需:约 21 分钟

本系列的第1 部分主要描述了通过使用BlazeDS 将Java 服务、PHP 以及Adobe Flash Builder 的用户界面与JMS 相集成。文章展示了只需区区几处配置改动,您就可以使用BlazeDS 通过MessageBroker servlet 把Flash Builder 所建立的用户界面与JMS 消息队列相连接。文章还涉及了整合PHP 和Java 及JMS 的另一种方法:使用REST(Representational State Transfer)Web 服务把消息发送到JMS 队列。

本系列的第2 部分则讨论整合PHP 和Java 的另外两个方法。第一种方法——桥接(bridging),让您可以在PHP 中使用Java 对象,从PHP 中通过Java 曝露的方法把消息发送到JMS 消息队列。第二种集成的方法是利用STOMP(Streaming Text Orientated Messaging Protocol)协议与ActiveMQ(JMS 的实现之一)进行通信。当ActiveMQ 接收到消息,ActiveMQ 会把消息放入JMS 队列,Adobe Flex 应用程序则从队列中接收消息。

通过桥接与 PHP集成

本系列的第 1 部分说明了如何使用 BlazeDS 和 JMS 在 Java 与 Flex 之间传递消息。其他技术也能够完成 PHP 与 Java 的集成,让您间接地把消息放入 JMS 队列。 Java/PHP 桥就是这些技术的一种,它允许您使用已配置好的、运行于 ActiveMQ 上的同一个 JMS 队列。使用 Java/PHP 桥,您可以写 PHP 脚本来调用 Java 类中的方法。此方法会把 JMS 消息放入消息队列。Flex 用户界面则使用 BlazeDS 来连接 JMS 队列,从队列中接收消息,正如它在 REST Web 服务中做的那样。

PHP/Java 桥的发布包里面有一个 JavaBridge.war 文件。解压此 WAR 包,把解压后的文件放进 ActiveMQ 的 webapps/JavaBridge 目录下,并在 conf/jetty.xml 配置文件中添加此应用程序。此 JavaBridge Web 应用程序包含了从 PHP 脚本接收消息的 Servlets,处理消息,然后运行 Java 类。

Java 示 **** 例

由于 PHP 脚本和 Java 类之间的通信可能会很慢,因此需创建一个 Java 类,在一个方法中来处理。这种做法就是著名的 Fa?ade 设计模式——在所暴露的简单方法背后隐藏了复杂的功能。

下面是 Java 实例的 Fa?ade 类,类名为 MessageHelper,包名为 com.example.bridge。

复制代码
import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.util.IndentPrinter;
public class MessageHelper {
private Destination destination;
private String user = ActiveMQConnection.DEFAULT_USER;
private String password = ActiveMQConnection.DEFAULT_PASSWORD;
public void sendMessage(String url, String subject, String messageText) {
Connection connection = null;
try {
boolean isTopic = true;
boolean isPersistent = false;
System.out.println("Using URL: <" + url + ">");
System.out.println("Using Subject: <" + subject + ">");
System.out.println("Sending Message Text: <" + messageText + ">");
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user, password, url);
connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
if (isTopic) {
destination = session.createTopic(subject);
} else {
destination = session.createQueue(subject);
}
// Create the producer.
MessageProducer producer = session.createProducer(destination);
if (isPersistent) {
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
} else {
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
}
TextMessage message = session.createTextMessage(messageText);
producer.send(message);
System.out.println("Done.");
// Use the ActiveMQConnection interface to dump the connection
// stats.
ActiveMQConnection c = (ActiveMQConnection)connection;
c.getConnectionStats().dump(new IndentPrinter());
} catch (Exception e) {
System.out.println("Caught: " + e);
e.printStackTrace();
} finally {
try {
connection.close();
} catch (Throwable ignore) {
}
}
}
}

此 Java 类只有一个方法——sendMessage(),该方法有三个参数:JMS 的目的地 URL 地址、所使用的 Topic 名及消息内容。

把以上写好的类放入一个 JAR 文件中,然后把此 JAR 文件放入 JavaBridge Web 应用程序的 WEB-INF/lib 文件夹下面。之所以要把该 JAR 文件放在 JavaBridge Web 应用程序的类路径(lib 目录)下,是因为 JavaBridge Web 应用程序实际负责实例化 JAR 包中的 Java 类。MessageHelper 类的这一方法与 Web Server 是在同一个虚拟机中执行的——在本例中,就是执行 Jetty 实例和 ActiveMQ 的那个虚拟机。

PHP 示 **** 例

下面的 PHP 脚本使用了 Java.inc 文件,它是 PHP/Java 桥自带的文件。然后 PHP 脚本创建 Java 对象并调用其方法:

复制代码
<?php
require_once ("java/Java.inc");
java_autoload('messageHelper.jar');
$helper = java('com.example.bridge.MessageHelper');
$url = 'tcp://localhost:61616';
$subject = '/topic/MyTopic/';
$message = 'Hello, world!!';
$helper->sendMessage($url, $subject, $message);
echo "Message sent";
?>

在 PHP 脚本中,java_autoload() 方法加载 JAR 文件。java() 方法使用 Java 对象全名来载入 Java 对象。 Java 对象加载后,PHP 脚本通过为 Java/PHP 桥配置的端点调用 SendMessage() 方法。

为 Java/PHP 桥配置端点需要在 java 目录的 java.inc 文件中进行配置。通过改变端点,您可以在不同的 Web 服务器中执行 PHP 脚本。如果您已经有一个配置了 PHP 的 Web 服务器,您可以把该校本放在一个 Web Document 目录下并执行它。要让您的 PHP 脚本运行正常,您还必须将发布包中的 java 目录放在与 PHP 脚本相同的目录下(查看 PHP/Java Bridge 以了解详情)。

在上例中,桥接只建于 PHP 和 Java 之间,使得 PHP 代码可以调用 Java 对象。而例子中不需要从 Java 到 PHP 的桥接。

实战例子:用BlazeDS发送和接收消息

要看实战的例子,先要启动 Flex 应用程序。在另一个浏览器中,运行连接到 PHP/Java 桥的 PHP 脚本。您会在 Flex 用户界面上看到“Hello, world”消息。

使用STOMP协议与PHP集成

STOMP 是另一种技术,您可以用它来弥合 PHP 和 ActiveMQ JMS 之间的鸿沟。在这个例子中,ActiveMQ 使用 STOMP 协议从 PHP 脚本接收消息,然后把消息路由到 JMS Topic,Flex 应用程序接收消息并在界面上显示消息。

STOMP**** 概述

STOMP 是一个协议,它可以使用多种不同的客户端发送消息。尽管 ActiveMQ 已内建了对 STOMP 的支持,你还是可以使用类似 StompConnect 这样的 STOMP 类库与 JMS 通信。

下面的例子说明了如何在 ActiveMQ 中使用内建的 STOMP 协议支持。与 STOMP 一起工作的消息代理(message broker)需要在 conf/activemq.xml 配置文件中打开:

复制代码
<transportConnectors>
<transportConnector name="openwire" uri="tcp://0.0.0.0:61616" />
<transportConnector name="stomp" uri="stomp://0.0.0.0:61613" />
</transportConnectors>

添加了 STOMP 代理的配置后,重启 ActiveMQ。当 ActiveMQ 启动时,它会把“STOMP 连接器已经启动”的消息写入日志文件:

INFO | Connector openwire Started

INFO | Listening for connections at: stomp://silverstreak.local:61613

从 PHP 脚本经由 STOMP 发送的消息被 ActiveMQ 接收,接收到的消息被放入 JMS 主题或 JMS 队列,由相同的消费者接收。经由 STOMP 发送消息还使得 Flex 界面无需修改代码或配置就能接收同样的消息。在这种方式下,利用 STOMP 将消息发送到 ActiveMQ,对应用程序的其它部分来说,是相当透明的。

PHP**** 代码

您可以使用下面的 PHP 脚本利用 STOMP 来把消息发送到与前面例子相同的 MyTopic JMS 主题(本文一直在使用)。代码使用的 Stomp.php 类来自于 FuseSource 。Stomp.php 类提供了一个从 PHP 发送消息的简单方法。要使用这个类,你必须下载该发布包并将其文件复制到示例脚本相同的目录中:

复制代码
try {
// include a library
require_once("Stomp.php");
// make a connection
$con = new Stomp("tcp://localhost:61613");
// connect
$con->connect();
// send a message to the queue
$con->send("/topic/MyTopic", "Hello, world");
echo "Sent message with body 'test'\n";
$con->disconnect();
} catch (Exception $e) {
var_dump($e->getMessage());
}
?>

此代码连接到 ActiveMQ 服务器的 61613 端口,并发送一个很短的文本消息(“Hello, world”)。然后,它从 STOMP 连接器断开连接。

ActiveMQ 把消息路由到相应的 JMS 主题。Flex 应用程序能够接收到这个消息,因为 Flex 订阅了此主题。

实战例子

要看到实战的例子,请再次打开 Flex 应用程序。另外打开一个浏览器,运行您刚才创建的 PHP 脚本,“Hello, world”消息将会显示到 Flex 应用程序的界面上。

使用 ****JNDI

为简单起见,本系列的所有例子均直接使用了队列名和主题名(比如:/topic/MyTopic)。然而,在使用 JMS 的生产环境中,JMS 主题名或队列名一般是使用 JNDI(Java Naming and Directory Interface)进行配置的,而不会采用硬编码的方式。

JNDI 是一个 Java 标准,它允许你抽象 JMS 队列名、主题名、甚至是主机名的实际名称。JNDI 有点像域名系统(DNS),使您能够使用主机名而不是 IP 地址来识别主机。使用 JNDI 可以让您随时调整服务器上的 JMS 主题或队列的位置和实现,而不必修改您的代码。

除了抽象主题名和队列名之外,JNDI 还提供了另一个有用的功能:能够使用 Java EE 的 JMS 对象接口来编写代码。使用接口而不是具体的实现,可以使您的 Java 代码不依赖于特定的供应商。

看看下面的 Java 代码例子:

复制代码
javax.naming.Context ctx = new javax.naming.InitialContext();
javax.jms.ConnectionFactory factory = (javax.jms.ConnectionFactory)ctx.lookup("ConnectionFactory");
javax.jms.Connection conn = factory.createConnection();
javax.jms.Destination destination = (javax.jms.Destination)jndiContext.lookup("MyTopic");
javax.jms.Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
// send the message...
javax.jms.MessageProducer producer = session.createProducer(destination);
javax.jms.TextMessage message = session.createTextMessage();
message.setText("Hello, world!");
producer.send(message);
conn.close();

以上 Java 代码没有使用 ActiveMQConnectionFactory 的具体实现,而是使用了 InitialContext 对象来“查找(lookup)”指定的连接器工厂实现。然后,代码使用 InitialContext 对象上相同的查询方法(lookup)来获取 JMS 主题的引用。这样,本例的代码中就不会包含对 ActiveMQ 的直接引用。

使用 JNDI 的缺点——除了要学习如何在 Java 代码中使用 JNDI 之外,还需要提供一些额外的配置,以获取初始的 JDNI 上下文。对于前者,ActiveMQ 提供了一个简单的 JNDI InitialContextFactory 以方便使用。(请参阅 ActiveMQ 支持页面以获取更多信息)。至于需要额外的配置,无需修改代码即可在不同厂商提供的应用服务器上部署和执行这一优点可以抵消掉这一瑕疵。如果您的环境有可能切换到不同的供应商,您可以考虑使用 JNDI 来帮助抽象细节。

网络考虑因素

此集成解决方案提供了 PHP 和 Flex 客户端通过 Java/JMS 技术在网络上进行通信的功能。因为您可以把不同的内容部署到不同的 Web 服务器,在评估集成技术时还需考虑网络访问的一些因素。

如果在 PHP、Flex 和 Java/JMS 服务之间存在防火墙,防火墙开放的端口可能会影响您选择用于集成的方法。由于 BlazeDS 是通过 MessageBroker Servlet 将 Flex 界面连接到 JMS 的,因此服务器只需标准的 80 端口(或 Web 应用服务器绑定的任何端口)能够访问即可。

ActiveMQ 使用非标准的端口来监听消息,但如果 ActiveMQ 与 BlazeDS 作为 Web 应用服务器运行在同一台机器上时,端口(“openwire”连接器的 61616 端口)问题只受限于本地接口,而不是公开暴露出来。

您的 Web 应用服务器可以在 80 端口暴露 REST Web 服务,使得跨网络和服务器进行集成相对简单。基于这个原因,许多人会选择 Web Services。

PHP/Java 桥使用了部署在 JavaBridge Web 应用程序中的一个 Servlet,通过 XML 流机制暴露 Java 类给 PHP。因为这个桥接是作为一个 Servlet 安装的,所以也可以从 Web 服务器的标准端口访问。

但是,使用 STOMP 协议需要在 PHP 脚本和(ActiveMQ 的)STOMP 消息代理之间开放一个非标准的端口。上面例子中开放的端口是 61613 端口。如果限制了从网络访问这个端口,那么 STOMP 或许并不是集成 PHP 脚本、Flex 界面及 Java/JMS 服务一个好的解决方案。

小结

JMS 是一个消息传递服务,支持主题和队列,其很多特性使其成为稳定消息传递的一个很好选择。BlazeDS 使得您无需付出很多工作量即可让 Flex 应用程序从 Flex 客户端发送消息到 JMS。

本系列的第1 部分介绍了JMS 的消息传递,并示范了如何配置BlazeDS 与JMS 队列进行通信。文章还介绍了使用Java 实现的REST Web 服务来集成PHP 应用程序和JMS 的方法,让您的Flex 用户界面可以从PHP 脚本收到消息。

本文则介绍了从PHP 发送消息到JMS 主题或队列的另外两种方法。PHP/Java Bridge 是一个开源项目,提供了一个从PHP 脚本调用Java 类的框架。通过编写单个的Java 类——即所谓的Fa?ade 模式,您的PHP 脚本就能够将消息发送到JMS,并且从Flex 界面接收到此消息。STOMP 是一个协议,它有多种语言的支持库。利用STOMP,您可以在Flex 应用中与JMS 消息代理通信并接收消息。

总之,这些不同的技术提供了整合PHP、Flex 或Java 应用的不同选项。整合现有的应用程序而不是重新开发它们,可以节省您的时间和精力,而且您也能自由选择适合您需要的最佳实现。

关于作者

Nathan A. Good 居住在 Minnesota 的 Twin 城地区。其专长是软件开发、软件架构和系统管理。平时不编写软件时,他喜欢组装 PC 和服务器、阅读和使用新技术,并鼓励他的朋友转用开源软件。他是许多书籍和文章的作者或合著者,其中包括《Professional Red Hat Enterprise Linux 3》、《Regular Expression Recipes: A Problem-Solution Approach》以及《Foundations of PEAR: Rapid PHP Development》。

查看英文原文: BlazeDS and JMS for PHP Developers, Part 2


译者简介:李强,计算机硕士,毕业于电子科技大学,目前在四川长虹电器股份有限公司技术中心从事研发工作,主要研究领域是 SOA、ESB、Web 服务以及分布式应用等。

感谢宋玮对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

2010-07-19 02:403595

评论

发布
暂无评论
发现更多内容

上新丨Kyligence Zen 上线海量指标模板,轻松变身指标达人

Kyligence

数据分析 指标管理 指标中台

云原生可观测套件:构建无处不在的可观测基础设施

阿里巴巴云原生

阿里云 云原生 可观测

焱融全闪系列科普|固态存储核心技术 SSD

焱融科技

云计算 分布式 高性能 文件存储 全闪存储

天翼云打造自研云操作系统TeleCloudOS4.0 推动算力蓬勃发展

Geek_2d6073

来自2年前端的面经

loveX001

JavaScript

盒马 iOS Live Activity &“灵动岛”配送场景实践

阿里巴巴终端技术

ios 灵动岛

CSS 边框也能动画?background-origin 和 -clip 来施加魔法~

掘金安东尼

CSS 11月月更

Java中的ArrayList类基础使用

共饮一杯无

Java ArrayList 11月月更

基于CSS mask和clip-path实现切角的技巧

南城FE

CSS css3 前端

深入理解JS作用域链与执行上下文

loveX001

JavaScript

VUE3+TS学习-项目搭建

肥晨

Vue3 脚手架 11月月更

谈谈企业级前端应用中通过 CSS 达到布局定制化的话题

Jerry Wang

angular web开发 SAP Fiori 11月月更

共筑行业标准,亚信科技AntDB数据库参与多项数据库行业标准研讨会

亚信AntDB数据库

AntDB aisware antdb AntDB数据库

被老板忽悠入局后,我如何在三年内让产品「起死回生」?

LigaAI

产品经理 产品管理 产品管理成功秘诀 产品负责人 企业号十月PK榜

带你了解NLP的词嵌入

华为云开发者联盟

人工智能 自然语言处理 华为云 企业号十月 PK 榜

WeOps赋能制造业数字化,助力坚美铝业IT高效管理

嘉为蓝鲸

DevOps 运维 AIOPS weops 嘉为蓝鲸

备战双11,送你一份解压壁纸!

OceanBase 数据库

震惊,改密码这件小事竟然让他差点累到吐血...

嘉为蓝鲸

运维 IT #WeOps

【LeetCode】交替合并字符串Java题解

Albert

算法 LeetCode 11月月更

前端面试指南之JS面试题总结

loveX001

JavaScript

2022年11月中国数据库排行榜:GaussDB获认证进前五,GBase得融资竞逐鹿

墨天轮

数据库 opengauss TiDB 国产数据库 KingBase

带你从0到1开发AI图像分类应用

华为云开发者联盟

人工智能 华为云 图像分类 企业号十月 PK 榜

Dive into TensorFlow系列(1)-静态图运行原理

京东科技开发者

人工智能 机器学习 tensorflow 动态图 静态图

Curve 文件存储:如何支撑百亿级文件?

网易数帆

文件存储 分布式存储 云原生存储 curve 企业号十月 PK 榜

Java 函数式编程

Ayue、

函数式编程

谈谈企业级前端应用 UI 界面增强实现的一些实际案例

Jerry Wang

angular web开发 SAP Hybris 11月月更

HDC 2022重磅首发《鸿蒙生态应用开发白皮书》,附全文

HarmonyOS开发者

HarmonyOS

vue2双向绑定原理:深入响应式原理defineProperty、watcher、get、set

肥晨

11月月更 vue响应式 响应式开发

如何使用netlify部署vue应用程序

肥晨

11月月更 网站托管 netlift

2022前端笔试题总结

loveX001

JavaScript

DevOps工具链的国产化之道

嘉为蓝鲸

DevOps 运维 IT

PHP开发者的BlazeDS和JMS指南,第二部分_Java_Nathan A. Good_InfoQ精选文章