论道WP(三):应用程序栏
作者通过具体翔实的例子介绍了Winodws Phone 7中应用程序栏的使用方式。
该内容已经被标记书签!
标记书签错误,请重试!

作者 Nathan A. Good 译者 李强 发布于 2010年7月19日
本系列的第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应用程序则从队列中接收消息。
本系列的第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类。
由于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脚本使用了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的桥接。
要看实战的例子,先要启动Flex应用程序。在另一个浏览器中,运行连接到PHP/Java桥的PHP脚本。您会在Flex用户界面上看到“Hello, world”消息。
STOMP是另一种技术,您可以用它来弥合PHP和ActiveMQ JMS之间的鸿沟。在这个例子中,ActiveMQ使用STOMP协议从PHP脚本接收消息,然后把消息路由到JMS Topic,Flex应用程序接收消息并在界面上显示消息。
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脚本利用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应用程序的界面上。
为简单起见,本系列的所有例子均直接使用了队列名和主题名(比如:/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中文站用户讨论组中与我们的编辑和其他读者朋友交流。
在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,本文详细介绍了Java SE1.6中对于锁的性能优化,以及锁的存储结构及升级过程。
本次分享将首先介绍现代富文本编辑器的组成和实现,然后结合UEditor的开发过程,与参会者分享UEditor在设计和实现的过程中,所涉及到的核心功能的细节实现。
本次演讲视频录制于百度技术沙龙。
我们所开发的应用程序大多都需要提供一个图形用户界面(GUI)。关于GUI应用的架构设计,已经有了Form & Control、MVC,、MVP、 Passive View等多种模式。模式可以帮助我们建立优雅的架构,但前提是弄清楚模式的应用场景。弄清楚GUI应用面临的设计上的问题,有助于我们正确的挑选设计方案。
MongoDB是一种非常易用的NoSQL方案,Brian C. Dilley在这篇文章里介绍了MongoDB的优劣势,并介绍了MJORM项目。MJORM用于MongoDB,是一个没有注解的Java ORM库。
随着网络基础设施的逐步成熟,从RPC进化到Web Service,并在业界开始普遍推行SOA,再到后来的RESTful平台以及云计算中的PaaS与SaaS概念的推广,分布式架构在企业应用中开始呈现出不同的风貌,然而殊途同归,这些分布式架构的目标仍然是希望回到建造巴别塔的时代,系统之间的交流不再为不同语言与平台的隔阂而产生障碍。
精益软件开发方法因其对市场和交付的重视和在各种场景下体现出的适应能力正在获得广泛的关注。特别是在精益创业(Lean Startup)渐渐兴起和技术日新月异的今天,其"极端"的思想也变得越来越必要和可行。 InfoQ就此主题对他做了深入的采访。
1 条回复
关注此讨论 回复