专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »PHP教程 » PHP开发者的BlazeDS和JMS指南 第一部分 »正文

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

来源: 发布时间:星期五, 2010年8月20日 浏览:7次 评论:0
  BlazeDS是来自Adobe公司个开源项目它可以让您Flex应用和数据服务进行连接JMS(Java消息服务)是用Java编写和服务相互通信种思路方法本文有助于您体会使用JMS优点以及在Flex应用中如何使用BlazeDS通过JMS和Java服务进行通信

  JMS概述

  JMS是个API(应用编程接口)标准它允许您使用Java EE技术发送和接收消息在Java社区很多软件Software商都提供了JMS商业和开源实现您可以根据自己需求自由选择软件Software商

  使用JMS优点

  使用JMS有几个优点包括抽象、可靠传递、异步消息以及故障转移和高可用性其中抽象是非常重要优点JMS消费者和生产者不必彼此相互依赖无论是消费者端还是生产者端代码都可以改变只要JMS消息保持两者间连接就不会中断

  JMS通常支持两种形式消息——持久化消息和非持久化消息非持久化消息是在内存中进行处理速度很快但可能会因系统故障而丢失消息持久化消息则会把消息写入磁盘即便系统发生故障也可找回消息但相应处理速度较慢不管是否使用事务处理JMS消息提供者都会确保所有持久化消息只被可靠传递异步消息传递则提供了发送消息而无需等待响应能力其在Web应用中非常有用当发送请求后应用无需阻塞或挂起等待响应完成这种消息传递类型对于需要长时间处理应用(如酒店预订或构建动态文档等应用)来说是个理想选择

  只要配置正确很多JMS实现都提供了故障转移和高可用性能力因此如果某个正在运行JMS服务器突然失效了相同JMS实现台服务器能够处理其负载对于需要提供业务连续性应用来说故障转移是个理想选择

  使用JMS和BlazeDS优点

  在使用BlazeDS连接JMS时Flex应用可以获得使用JMS所有好处而过去这些好处往往只有完全在J2EE平台上实现Web应用才能享受

  使用BlazeDS和JMS向服务发送消息可以让您Flex应用开发更加独立于服务服务JMS实现甚至可以在更换软件Software供应商而您Flex应用不用做任何修改

  使用BlazeDS和JMS个主要优点是如果您在使用JMS的前正在使用超文本传输协议(HTTP)那么您Flex应用代码基本不需要做什么改变BlazeDS会为您处理所有细节

  理解JMS消息

  JMS提供了两种类型消息传递模型:点对点(P2P)和发布/订阅(pub/sub)模型简单地说发布/订阅是对多方式广播消息而点对点则是方式传递消息

  在JMS中消息客户端被称为JMS客户端;而消息系统则被称为面向消息中间件(MOM——Messaging Orientated Middleware)它也是JMS提供者另外产生消息JMS客户端被称为是生产者而接收消息JMS客户端被称为消费者

  P2P模型

  P2P消息模型允许JMS客户端通过名为队列(Queue)虚拟信道发送和接收消息JMS队列可视为消息容器就像个邮箱JMS发送者推送条消息到JMS消息队列就如同寄件人把封信件放到了邮箱而后接收者从邮箱中获得消息并对的采取某种动作就像邮箱中信件使用JMS队列从发件人发送消息由单个接收者读取尽管JMS对于P2P也支持类似于发布/订阅模型所使用“推”方式传统P2P模型却是个基于“拉”或基于“轮询”模型是从队列中请求消息而不是把消息推送到客户端

  可能用到JMS消息和Flex客户端个例子是:从Flex客户端个进程该进程需要服务层花费些时间才能完成比如创建个按需定制PDF文件

  发布/订阅模式

  在发布/订阅模式中生产者可以通过名为主题(Topic)虚拟信道发送个信息给多个消费者主题和印刷杂志类似:订阅者向出版商注册订阅接收指定杂志出版商定期向区别订阅者发送同杂志副本发布/订阅模型总来说是基于推模型消息被广播到消费者而不是通过请求或拉方式

  使用JMS主题您可以从服务层次发送信息到多个Flex客户端在Flex客户端使用JMS主题个例子是用户上线在这个例子中当用户登录到该系统服务层会经由JMS主题发送个消息告诉其他所有Flex客户端该用户已上线

  JMS消息

  JMS提供种方式来构建信息使得主题和队列使用起来更加容易当编写Java代码时JMS API提供思路方法能以方式来正确构建消息而使用BlazeDS个好处是您不必担心怎样创建正确信息BlazeDS会辅助实现这

  JMS实现

  JMS实现有若干既有开源项目也有商业项目本文使用JMS实现是ActiveMQ它是Apache软件Software基金会个开放源码项目以 Apache许可证发布ActiveMQ除了提供个JMS实现外还提供使用其它编程语言发送消息功能包括PHP其它JMS实现还包括 IBMWebSphere MQJBossHornetQ(注:前身是JBoss Messaging开放消息队列)以及OpenJMS

  配置BlazeDS使用JMS

  若要BlazeDS使用JMS其配置包括:建立正确端点(endpo)并在终点(destination)配置中设置JMS属性本文举例用到了个简单Flex界面、BlazeDS库以及ActiveMQ

  JMSAdapter

  当消息到达MessageBroker Servlet后BlazeDS使用JMSAdapter来完成Flex应用和JMS实现的间消息转换JMSAdapter在messages-config.xml文件中配置:

<adapters> 
 <adapter-definition id="actionscript" ="flex.messaging.services.messaging.adapters.ActionScriptAdapter" default="true" /> 
 <adapter-definition id="jms" ="flex.messaging.services.messaging.adapters.JMSAdapter" /> 
</adapters> 


  端点区别

  定要记住BlazeDSJava库和MessageBroker servlet需要进行配置并运行于Web容器由于MessageBroker必须处于运行状态使用JMS适配器终点(destination)仍要使用AMF(Adobe Action Message Format)通道在本例中使用端点是:

<?xml version="1.0" encoding="UTF-8"?> 
<services-config> 
  <services> 
    <service- file-path="messaging-config.xml" /> 
  </services> 
 
  <security/> 
 
  <channels> 
   <channel-definition id="my-amf" ="mx.messaging.channels.AMFChannel"> 
     <endpo url="http://{server.name}:8161/blazeds/messagebroker/amf" ="flex.messaging.endpos.AMFEndpo"/> 
   </channel-definition> 
 
   <channel-definition id="my-streaming-amf" ="mx.messaging.channels.StreamingAMFChannel"> 
     <endpo url="http://{server.name}:8161/blazeds/messagebroker/streamingamf" ="flex.messaging.endpos.StreamingAMFEndpo"/> 
   </channel-definition> 
 
   <channel-definition id="my-polling-amf" ="mx.messaging.channels.AMFChannel"> 
     <endpo url="http://{server.name}:8161/blazeds/messagebroker/amfpolling" ="flex.messaging.endpos.AMFEndpo"/> 
     <properties> 
      <polling-enabled>true</polling-enabled> 
      <polling-erval-seconds>1</polling-erval-seconds> 
     </properties> 
   </channel-definition> 
  </channels> 
</services-config> 


  JMS属性

  JMS需要些自己配置比如连接工厂用于建立JMS连接JNDI(Java命名和目录接口)队列名或主题名也是使用JNDI进行解析 JNDI是个Java API允许把资源物理位置抽象成名字JNDI常见使用方法是数据库命名应用使用此JNDI名获得数据库连接

  除了连接工厂、主题或队列JNDI名JMS变量还允许您定义用户证书、消息类型、终点类型等等下面展示是在本例中使用JMS属性:

<destination id="my-jms-destination"> 
  <properties> 
   <jms> 
     <destination-type>Topic</destination-type> 
     <message-type>javax.jms.TextMessage</message-type> 
     <connection-factory>ConnectionFactory</connection-factory> 
     <destination-jndi-name>dynamicTopics/MyTopic</destination-jndi-name> 
     <delivery-mode>NON_PERSISTENT</delivery-mode> 
     <message-priority>DEFAULT_PRIORITY</message-priority> 
     <acknowledge-mode>AUTO_ACKNOWLEDGE</acknowledge-mode> 
     <initial-context-environment> 
      <property> 
        <name>Context.INITIAL_CONTEXT_FACTORY</name> 
        <value>org.apache.activemq.jndi.ActiveMQInitialContextFactory</value> 
      </property> 
      <property> 
        <name>Context.PROVIDER_URL</name> 
        <value>tcp://localhost:61616</value> 
      </property> 
     </initial-context-environment> 
   </jms> 
  </properties> 
  <channels> 
   <channel ref="my-amf" /> 
  </channels> 
  <adapter ref="jms" /> 
</destination> 


  您可以查看BlazeDS文档以获得进属性解释

  从BlazeDS发送消息

  要尝试本文例子请在创建您测试Flex项目的前按照下面步骤行事下载ActiveMQ 2进制发布包并解压您可以启动ActiveMQ并完成ActiveMQ文档中验证步骤但在继续下步的前请先关闭ActiveMQ

  下载BlazeDS 2进制发布包

  首先要下载BlazeDS 2进制发布包:

  将BlazeDS发布包blazeds.war解压到ActiveMQwebapps目录下这么做可保证您运行例子中只使用了ActiveMQ

  在Jetty服务器中建立Web应用上下文Jetty是个Web容器ActiveMQ 2进制发布包自带了Jetty如要增加上下文需修改jetty.xml文件它位于ActiveMQ目录下conf目录:

<webAppContext contextPath="/blazeds" resourceBase="${activemq.base}/webapps/blazeds" logUrlOnStart="true"/> 

  启动ActiveMQ在浏览器地址栏输入http://localhost:8161/blazeds应该可以看到BlazeDS目录列表步是验证你已经把BlazeDS WAR放在正确位置并配置正确

  创建个Flex项目它包含两个配置文件配置文件位于src/WEB-INF/flex目录分别为:messaging-config.xml和services-config.xml使用文章前述例子来设置JMS终点并添加JMSAdapter

  把Flex应用项目中services-config.xml和messaging-config.xml文件复制到ActiveMQwebapps/blazeds/WEB-INF/flex目录

  发送消息(举例)

  为测试从Flex发送消息本文使用了ActiveMQ自带命令行例子为从Flex应用中发送条消息到命令行客户端您可以在Flex代码中建立个生产者(producer)然后用区别参数运行命令行例子并查看结果

  您需要在Flex应用中创建个生产者来发送消息作为个终点这个新生产者将使用配置在messaging-config.xml文件中my-jms-destination下面这个例子是个非常简单带有消息生产者(producer)Flex表单:

<?xml version="1.0" encoding="utf-8"?> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="consumer.subscribe"> 
  <mx:Script> 
   <![CDATA[ 
     import mx.messaging.messages.IMessage; 
     import mx.messaging.messages.AsyncMessage; 
     import mx.messaging.events.MessageEvent; 
     private function sendMessage(value : String) : void 
     { 
      var message : IMessage =  AsyncMessage; 
      message.body = value; 
      producer.send(message); 
     } 
   ]]> 
  </mx:Script> 
  <mx:Producer id="producer" 
   channelConnect="trace('producer connected')" 
    destination="my-jms-destination" 
    fault="trace(event.faultDetail)" 
  /> 
  <mx:VBox> 
   <mx:Form> 
     <mx:FormItem label="Message:"> 
     <mx:TextInput id="textInput" /> 
   </mx:FormItem> 
   </mx:Form> 
   <mx:Button id="sendButton" label="Send Message" click="sendMessage(textInput.text)" /> 
  </mx:VBox> 
</mx:Application> 


  界面上有个按钮sendButton点击此按钮会sendMessagesendMessage先创建个 AsyncMessage其是IMessage接口个实现然后使用producersend思路方法发送此消息赋值给fault属性 trace思路方法会把给定信息打印到控制台从而帮助您调试任何可能发生问题

  验证消息:运行Flex应用;切换到命令行运行ActiveMQ自带消费者(consumer)例子脚本如下:

$ ant consumer -Dtopic=true -Dsubject=MyTopic -Dmax=2 

  如果你输入框中输入消息然后点击发送消息按钮该消息会出现在消费者端命令行上在收到两条消息后消费者端命令行例子会自动退出

  接收消息(举例)

  要接收JMS消息您需要构建个使用JMS终点消费者(consumer)在例子中为简单起见消费者重用了生产者用来发送消息终点创建消费者代码大致如下:

<mx:Consumer id="consumer" channelConnect="trace('consumer connected')" 
  channelFault="trace(event.faultDetail)" 
  fault="trace(event.faultDetail)" 
  destination="my-jms-destination" 
  message="messageHandler(event)" /> 
... 
<mx:TextArea id="results" width="100%" /> 


  在<mx:Script>代码块中处理消息大致如下:

private function messageHandler(event : MessageEvent) : void { 
  results.text  event.message.body + "\n"; 
} 


  添加了代码后启动Flex应用当Flex应用启动后在命令行运行生产者例子脚本如下:

ant producer -Dtopic=true -Dsubject=MyTopic -Dmax=5 

  消息将出现在Flex文本框中

  通过REST服务和PHP集成

  Web服务是集成PHP Web应用和Java思路方法的REST Web服务在Java中作为Servlets以及在PHP中作为脚本实现都比较容易

  REST概述

  REST Web服务比SOAP Web服务更为简单REST Web服务没有个标准消息格式(例如单个网页可以是个REST Web服务)URL地址就是服务端点(endpo)而返回Web页面则是该服务响应

  编写REST Web服务个优点是可被多种类型客户端使用REST Web服务举例如下它作为个Java Servlet能被其它语言如PHP而无需修改服务

  Java Servlet举例

  本例使用了个简单Java Servlet来作为REST Web服务此Servlet处理PUT请求从PUT请求内容和各种参数中得到消息例如:得到目标对象(JMS终点名字)此消息是否是个主题 JMS连接使用URL等

package com.example.servlets; 
 
import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.net.URLDecoder; 
 
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 javax.servlet.ServletException; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
 
import org.apache.activemq.ActiveMQConnection; 
import org.apache.activemq.ActiveMQConnectionFactory; 
import org.apache.activemq.util.IndentPrer; 
 
public  MessageService extends HttpServlet { 
  private  final long serialVersionUID = -8129137144911681674L; 
 
  private Destination destination; 
  private String user = ActiveMQConnection.DEFAULT_USER; 
  private String password = ActiveMQConnection.DEFAULT_PASSWORD; 
 
  @Override 
  protected void doPut(HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, IOException { 
 
    Connection connection = null;       
 
    try { 
      boolean isTopic = "true".equals(request.getParameter("topic")); 
      boolean isPersistent = "true".equals(request.getParameter("persistent")); 
      String subject = request.getParameter("subject"); 
      String url = URLDecoder.decode(request.getParameter("url"), "UTF-8"); 
      String messageText = ""; 
 
      BufferedReader buffer =  BufferedReader( InputStreamReader(request.getInputStream)); 
 
      messageText = buffer.readLine; 
 
      .out.prln("Using URL: <" + url + ">"); 
      .out.prln("Using Subject: <" + subject + ">"); 
      .out.prln("Sending Message Text: <" + messageText + ">"); 
 
      ActiveMQConnectionFactory connectionFactory =  ActiveMQConnectionFactory(user, password, url); 
      connection = connectionFactory.createConnection; 
      connection.start; 
 
      Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 
 
       (isTopic) { 
        destination = session.createTopic(subject); 
      }  { 
        destination = session.createQueue(subject); 
      } 
 
      // Create the producer. 
      MessageProducer producer = session.createProducer(destination); 
       (isPersistent) { 
        producer.DeliveryMode(DeliveryMode.PERSISTENT); 
      }  { 
        producer.DeliveryMode(DeliveryMode.NON_PERSISTENT); 
      } 
 
      TextMessage message = session.createTextMessage(messageText); 
 
      producer.send(message); 
 
      .out.prln("Done."); 
 
      // Use the ActiveMQConnection erface to dump the connection 
      // stats. 
      ActiveMQConnection c = (ActiveMQConnection)connection; 
      c.getConnectionStats.dump( IndentPrer); 
 
    } catch (Exception e) { 
      .out.prln("Caught: " + e); 
      e.prStackTrace; 
    } finally { 
      try { 
        connection.close; 
      } catch (Throwable ignore) { 
      } 
    } 
 
  } 
 
} 


  除了用ActiveMQ特定类你还可以使用JNDI来写代码

  编译后Servlet类文件(比如前面MessageService类)必须放在ActiveMQwebapps目录下要添加新目录则需要在conf目录jetty.xml配置文件中添加入口(和前面步骤4相似)

  PHP举例

  PHP脚本使用CURL库(译者注:原文 CURL库链接有错)REST服务将数据发送到REST服务URL(由Java Servlet处理)如果您PHP版本没有包含CURL库您可以使用Ajax来REST Web服务在Web应用实际产品中Ajax可能会提供更好用户体验  

  PHP脚本包含个表单来提交自身当提交表单时该脚本从文本框取得消息并把消息作为数据发送到REST服务URL请看下面例子:

<?php 
   (is($_POST['submit'])) { 
   $url = 'http://localhost:8161/messageservice/?url=tcp://localhost:61616&subject=MyTopic&topic=true'; 
   function doPut($ch, $a_data) { 
     curl_opt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); 
     curl_opt($ch, CURLOPT_HTTPHEADER, .gif' />('Content-Length: '.strlen($a_data))); 
     curl_opt($ch, CURLOPT_POSTFIELDS, $a_data); 
      curl_exec($ch); 
   } 
   $data = $_POST['message']; 
   $ch = curl_init; 
   curl_opt($ch, CURLOPT_URL, $url); 
   $response = doPut($ch, $data); 
   echo 'Message sent'; 
  }  { 
   ?> 
     <html><head><title>Post a message</title></head> 
     <body> 
     <form action="<?php echo $_SERVER['PHP_SELF'];?>" method="post"> 
     <p> 
      <label for="message">Message: 
        <input type="text" id="message" name="message" /> 
      </label> 
     </p> 
     <input type="submit" value="submit" name="submit" id="submit" /> 
     </form> 
     </body> 
   </html> 
   <?php 
  } 
?> 




  在URL上传递JMS服务器topic、subject和URL信息都赋值给了$url

  用BlazeDS发送/接收举例

  要想看BlazeDS发送/接收例子启动Flex应用当应用打开在区别浏览器上打开PHP脚本给消息框添加个值然后单击提交消息框值将会出现在Flex应用文本框中

  小结

  JMS是个消息传递服务支持主题和队列两种模式以及其它很多特征是可靠消息传递不错选择 BlazeDS可以让您只需做少量工作即可完成从Flex客户端向JMS发送消息

  PHP应用可以以多种方式连接到JMS使用REST Web服务是把PHP和Java应用整合在种方式——REST Web服务提供了种相对简单接口供客户端使用使用Java实现REST服务您可以利用现有Java代码来发送JMS消息

  本系列第2部分主要讲通过JMS整合PHP和Flex应用其它思路方法:PHP / Java桥和STOMP

  译者注:STOMPStreaming Text Orientated Message Protocol是流文本定向消息协议种为MOM(Message Oriented Middleware面向消息中间件)设计简单文本协议



标签:
0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: