一、最近项目中要使用pushlet作为推送消息的技术框架,所以特地学习了一下。我们重点记录项目中的实际使用过程和解决问题的办法。首先需要了解的是,Pushlet 是一个开源的 Comet 框架,Pushlet 使用了观察者模式:客户端发送请求,订阅感兴趣的事件;服务器端为每个客户端分配一个会话 ID 作为标记,事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。表面上是服务器推,实现是还是客户端拉。这张原理图画的不错:
1.browser发送join命令到server,server产生唯一的ID给client端,用于标识这次会话的唯一性,Pushlet是用java.rmi.server.UID产生的唯一的标志会话的标志,此时server会把sessionID作为key,session对象作为value,存放到HashMap里面,然后通过response.getWriter().println()回调给browser
2.browser拿到sessionID,并发送listen命令,listen命令,有subject,提交给server,server首先验证Session HashMap里面有没有这个sessionID,验证通过后,回调给客户端listen_ack消息,同时开始把数据放入eventQueue中,并update给客户端,这里的queue符合生产消费模式,eventsource是生产线程,它负责把数据enqueue入队列,如果满则等待,直到消费线程消费,消费线程负责消费,由于eventsource是sleep一段时间才enqueue,消费线程没有sleep,它采取的是while(alive)的方式,因此,从这里来说,消费速度应该快于生产速度的。
二、去官网下载jar包,可惜官网总是访问不了或者下载不了,所以有需要的可以直接去我的项目中拿,项目已经放到了github上面,链接在文章末尾。
1.搭建一个简单的web项目,项目结构如下图:
接下来对各个文件一一说明:首先下载jar包和js文件分别放在lib和webcontent目录下,还有两个properties配置文件,放在class下面,pushlet还使用了log4j,所以也吧log4j的jar包和properties文件放进来。剩下的就是我们的index.jsp文件和HelloWorldPlushlet.java文件和web>xml文件。
首先看web.xml文件里面的代码,我们配置了pushlet的servlet,意思是当访问链接是/pushlet.srv时,交给pushlet处理。这里的/pushlet.srv是pushlet默认的,无需修改,要是修改,在js里面也要修改,讲到js的时候会说明。
1 <!-- Define the pushlet servlet --> 2 <servlet> 3 <servlet-name>pushlet</servlet-name> 4 <servlet-class>nl.justobjects.pushlet.servlet.Pushlet</servlet-class> 5 <load-on-startup>3</load-on-startup> 6 </servlet> 7 <!-- Define the Servlet Mappings. --> 8 <!-- The pushlet --> 9 <servlet-mapping> 10 <servlet-name>pushlet</servlet-name> 11 <url-pattern>/pushlet.srv</url-pattern> 12 </servlet-mapping>
接下来是我们写我们的后台代码,新建类HelloWorldPlushlet,重要的是我们里面要写一个内部类,这个内部类要继承EventPullSource,然后重写两个方法,一个是睡眠时间设置,一个是生成事件的,这个方法里面可以写我们处理的业务,然后将这些业务生成事件event交给前台。在这里我们生成了“”Event event = Event.createDataEvent("/test"); 事件,并且通过key-value形式传递了一个中文字符串。
package com; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.Date; import nl.justobjects.pushlet.core.Event; import nl.justobjects.pushlet.core.EventPullSource; public class HelloWorldPlushlet { static public class HwPlushlet extends EventPullSource { // 休眠五秒 执行一次pullEvent @Override protected long getSleepTime() { return 5000; } @SuppressWarnings("deprecation") @Override protected Event pullEvent() { Event event = Event.createDataEvent("/test"); try { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String text = format.format(new Date()); String str = "传递中文测试!" + text + "!"; str = URLEncoder.encode(str,"UTF-8"); event.setField("cnmess", str); } catch (Exception e) { event.setField("mess", "异常错误!"); } return event; } } }
写好后台代码后,还要在配置文件中注册为事件源,打开pushlet.properties配置文件,事先已经有了几个source,我们把source1改成我们刚刚写好的的后台代码。source1=com.HelloWorldPlushlet$HwPlushlet
source1=com.HelloWorldPlushlet$HwPlushlet source2=nl.justobjects.pushlet.test.TestEventPullSources$SystemStatusEventPullSource source3=nl.justobjects.pushlet.test.TestEventPullSources$PushletStatusEventPullSource source4=nl.justobjects.pushlet.test.TestEventPullSources$AEXStocksEventPullSource source5=nl.justobjects.pushlet.test.TestEventPullSources$WebPresentationEventPullSource source6=nl.justobjects.pushlet.test.TestEventPullSources$PingEventPullSource
最后打开index.jsp页面写好代码,引入js文件,PL._init(); 初始化初始化pushlet客户端, PL.joinListen('/test'); 设定监听主题:与服务器端的主题完全一致,onData()方法用来接收事件和处理事件的。
<script type="text/javascript" src="ajax-pushlet-client.js"></script> <script type="text/javascript"> PL._init(); PL.joinListen('/test'); function onData(event) { //document.getElementById("mess").innerHTML=decodeURIComponent(event.get("cnmess")); alert(decodeURIComponent(event.get("cnmess"))); } </script>
好这个时候我们可以启动项目了,打开浏览器观察效果,每隔5秒钟就会接收到后台传递给我们的消息,效果如图:
大概的一个流程就是,我们在前台监听订阅了一个事件,然后通过js发送请求建立长连接,并且实际是通过轮询的方式不断请求后台,后台发布这个事件后,将消息定时的推送给订阅了此事件的前台。这样一个简单的demo就处理好了,接下来会记录实际项目中使用及分析源码。demo上传至github上面了,有兴趣可以自行下载。链接:https://github.com/MrLiu1227/pushlet.git