`
edwin492
  • 浏览: 115486 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

pushlet源码学习

阅读更多

 

Protocol: 一些常量的定义

Config: 加载和维护配置信息,如加载Pushlet.properties配置文件

SessionManager: 管理session的整个生命周期

EventSourceManager: 事件源管理类

Controller: 对来自客户端的请求的处理类,包含请求的事件的各种处理方法(封装响应事件ResponseEvent)

Subscriber: 订阅信息的添加删除,及事件推送等。

Dispatcher: 分配事件给订阅者

首先加载Pushlet类,它为一个servlet实现Protocol接口。

Pushlet中的init方法:

1. 取得路径 2. 加载配置文件 3.日志初始化 4. 初始化SessionManager 5. 初始化Dispatcher 6. 加载事件源

 

public void init() throws ServletException {
		try {
			// Load configuration (from classpath or WEB-INF root path)
			String webInfPath = getServletContext().getRealPath("/") + "/WEB-INF";
			Config.load(webInfPath);

			Log.init();
// Start session manager  通过单例模式获取sessionManager实例
			SessionManager.getInstance().start();

			// Start event Dispatcher
			Dispatcher.getInstance().start();
            if (Config.getBoolProperty(Config.SOURCES_ACTIVATE)) {
             //判断配置文件中是否设定为使用事件源,是则加载sources.properties
             //并对其中的所有事件源创建单独的守护进程并激活。
				EventSourceManager.start(webInfPath);
			} else {
				Log.info("Not starting local event sources");
			}
}

 SessionManager中的start方法通过JDK中的Timer类,重复执行任务。

 

public void start() throws PushletException {
		if (timer != null) {
			stop();
		}
		timer = new Timer(false);
		timer.schedule(new AgingTimerTask(), TIMER_INTERVAL_MILLIS, TIMER_INTERVAL_MILLIS);
		info("started; interval=" + TIMER_INTERVAL_MILLIS + "ms");
	}

 AgingTimerTask类即定义的任务,在其中不断判断sessionCache中的所有session是否超时,若超时则停止session

在定时器的run方法中调用apply方法,在这里应用了Visitor模式,apply方法即visitor提供的对所有元素访问的接口,Session即被访问的元素。在SessionManager中有Session[] sessionCacheMap sessions变量,前者用于缓存可修改的session,后者保存活跃的session。在apply中访问所有sessionCache中的session,通过反射访问AgingTimerTask中的回调方法visitVisist方法则用于判断此session是否已超时。

 

public AgingTimerTask() throws PushletException {
			try {
				// Setup Visitor Methods for callback from SessionManager
				Class[] argsClasses = {Session.class};
				visitMethod = this.getClass().getMethod("visit", argsClasses);//通过反射取得此类中的visit方法
			} catch (NoSuchMethodException e) {
				throw new PushletException("Failed to setup AgingTimerTask", e);
			}
		}
		/**
		 * Clock tick callback from Timer.
		 */
		public void run() {
			long now = Sys.now(); //获取当前时间
			delta = now - lastRun; //两次时间差
			lastRun = now; //将当前时间设为上一次是时间
			debug("AgingTimerTask: tick");
			// Use Visitor pattern to loop through Session objects (see visit() below)
			getInstance().apply(this, visitMethod, new Object[1]);
		}
		/**
		 * Callback from SessionManager during apply()
		 */
		public void visit(Session aSession) {
			try {
				// Age the lease
				aSession.age(delta); //减少session的生存时间
				debug("AgingTimerTask: visit: " + aSession);
				// Stop session if lease expired 超时则停止session
				if (aSession.isExpired()) {
					info("AgingTimerTask: Session expired: " + aSession);
					aSession.stop();
				}
			} catch (Throwable t) {
				warn("AgingTimerTask: Error in timer task : " + t);
			}
		}

 Dispatcher初始化很简单,创建一个SessionManagerVisitor实例,其为visitor模式中的visitor。其构造方法中将visitMulticastvisitBroadcast方法以Method存入一个Map中。这两个方法即在visitor中单独访问元素的visit方法。

       最后若使用事件源(sources.activatetrue),将加载事件源配置文件,并对其中的所有事件创建守护线程并激活线程。在EventSourceManager中创建一个全局的事件源集合,现调用activate()激活事件源,此方法应用templates模式其实现由其子类EventPullSource实现,此类中便是对线程进行管理。在线程的run()中产生事件并多点发布。线程每睡眠一段时间便发布一次时间。

 

public void run() {
		Log.debug(getClass().getName() + ": starting...");
		alive = true;
		while (alive) {
			try {//getSleepTime()由继承EventPullSource的子类实现
				Thread.sleep(getSleepTime());
				// Stopped during sleep: end loop.
				if (!alive) {
					break;
				}
				// If passivated wait until we get
				// get notify()-ied. If there are no subscribers
				// it wasts CPU to remain producing events...
				synchronized (this) {
					while (!active) {
						Log.debug(getClass().getName() + ": waiting...");
						wait();
					}
				}
			} catch (InterruptedException e) {
				break;
			}
			try {
				//pullEvent()由继承EventPullSource的子类实现
				Event event = pullEvent();
				// 多点发布事件
				Dispatcher.getInstance().multicast(event);
			} catch (Throwable t) {
				Log.warn("EventPullSource exception while multicasting ", t);
				t.printStackTrace();
			}
		}
		Log.debug(getClass().getName() + ": stopped");
	}

 至此Pushlet的初始化即完成。

当收到http请求时无论doGet还是doPost都是创建一个事件,事件Event通过一个HashMap来保存”p_event”事件类型及其属性,最后都调用doRequest进行处理。其中doGet针对普通请求,doPost针对xml处理。

doRequest处理中,当事件类开为”join”时说明还未创建session,此时创建一个新的session,否则通过Event中保存的SessionID获取session。在session在创建过程中,包括随机生成sessionid并依据session生成ControllerSubscriber实例赋给session

然后创建一个Command对象,调用Controller中的doCommand执行。Command为对request,response,event等信息的一个封装。

doCommand中执行如下:

更新Session的存活时间。重新设置为默认值。

设置 Session中的address为客户端请求的IP地址。

根据事件类型执行相应的方法。

Refresh:  Command的响应事件中加入一个”refresh-ack”刷新确认事件。

Subscribe: 订阅

调用Controller中的doSubscribe(),当事件中存在主题Subject时,首先获取初始化时创建的订阅者Subscriber对象,然后调用Subscriber中的addSubscriber创建一订阅信息,添加到一HashMap的全局变量subscribers中,同时返回此订阅。订阅创建即为创建一个subscription对象,在其中设置其属性subject,subjects,label其中subjects为一数组变量,存储subject中包含的所有主题。最后设置相关信息到responseEvent响应事件中,将相应事件封装到Command中。

Unsubscrib: 退订主题,将Map类型的subscribers中的订阅移除。

Join: 将请求的此session加入到SessionManager中的Map类型的sessions中,并设置sessionformate等信息。

Listen: 主要是确定订阅信息的转送方式mode,包含三种stream\pull\pollStream是发送一连串的事件(http长链接),即记录是不停止的。Pullpoll(客户端定时刷新服务端产即推送)是一个完整的记录返回的。配置文件中的listen.force.pull.all设置是否全部使用pull

Join-listen: joinlisten的集合。

Leave: 停止session,也即移除所有的订阅信息。

Hb: heartbear心跳,只是设置心跳事件给客户端。

Publish: 发布事件,若请求中有p_to(sessionid),即发送目标,将进行单播,否则为多播。单播时,将请求事件进行浅克隆,将克隆事件发送给目标事件的订阅者。onEvent()中若请求事件已激活、未超时且事件队列未满则加入事件队列,否则停止session。广播时调用上面介绍的apply()

 

// Send Event to subscriber.
		session.getSubscriber().onEvent((Event) event.clone());

 无论是哪种事件类型,最后都是将信息封装在responseEvent中,然后封装在Command中。

若请求事件为listenrefresh则只要存在连接就不断循环从队列中获取事件推送到客户端,不同的mode下进行不同的处理,添加心跳包到队列中等操作。在推送时应用到adapter模式,在command中有方法createClientAdapter,内容为根据开始设置的session中的format值来实例化不同的适配器类。包含jsjava序列化对象、xml等。其它的事件类型直接通过适配器推送。

 

pushlet服务端的代码其实就是一个中间过渡的过程,客户端传入请求事件及参数,服务端根据请求事件做一定的处理,再返回一个事件及传入的参数,客户端再根据返回的事件选择相应的回调函数获取参数进行操作,回调函数就由自己去实现。

相关资料:

http://blog.csdn.net/yxw246/article/details/2418255这个分析的很透彻

http://blog.csdn.net/anghlq/article/details/5869233

 

分享到:
评论

相关推荐

    Pushlet学习(二) -- Pushlet CookBook部分翻译 + 注释

    5. Pushlet源码分析: 了解Pushlet的源码可以帮助我们更好地理解其实现机制,包括如何管理HTTP连接、数据序列化和反序列化、以及错误处理等。源码研究对于定制Pushlet的行为或扩展其功能非常有价值。 6. Pushlet...

    pushlet测试示例

    pushlet源码demo,提供有需要的同学学习,如有更好的实现或建议,欢迎提出

    pushlet.jar 和示例工程

    "pushlet.jar 和示例工程"是一个专注于实现服务器端向客户端主动推送消息的框架,它在Web开发领域中扮演着重要角色。...而提供的压缩包资源则为学习和实践Pushlet提供了便利,是深入研究和应用这一框架的重要资料。

    pushlet的JAR包和文档

    综上所述,这些资源为学习和使用Pushlet提供了全面的支持,包括理论介绍、源码分析、实践示例和测试材料。对于想要深入理解和应用Comet技术,尤其是使用Java实现服务器推送的开发者而言,这些都是非常宝贵的参考资料...

    服务器推送——PushLet的应用<一>

    本文将深入探讨一种名为PushLet的服务器推送框架,并通过源码分析,揭示其工作原理与应用。 PushLet是一个轻量级的Java服务器推送框架,它基于HTTP长连接,利用了HTTP 1.1的Keep-Alive特性,实现了服务器到客户端的...

    pushlet的笔记

    【Pushlet笔记】是关于一个开源工具的详细学习记录,主要涵盖了Pushlet的源码解析、功能使用以及二次开发等内容。Pushlet是一个基于Java的实时推送框架,它允许服务器向客户端实时发送数据,而无需客户端频繁发起...

    pushlet简单示例

    3. **安装与配置**:指导如何下载Pushlet源码,配置开发环境,如Java运行环境(JRE)和构建工具(如Ant或Maven)。 4. **运行示例**:展示一个简单的应用示例,可能包括创建一个推送服务器端点,编写客户端连接脚本...

    pushlet_向在线的特定用户发送消息的单线程应用

    标题中的“pushlet”是指Pushlet,一种基于Comet技术的服务器推送机制。...在“pushlet_向在线的特定...通过研究提供的源码和工具,开发者可以学习如何构建一个简单的实时消息推送系统,特别是针对特定在线用户的推送。

    java服务端推送实例-pushlet-及中文问题

    这可能需要修改Pushlet源码或在Servlet配置中指定。 3. 在发送中文数据时,确保数据已经被正确地编码为字节流,然后再传递给Pushlet进行推送。 在提供的项目说明文档中,应当包含了具体的配置和代码示例,指导如何...

    Pushlet简单应用小结

    【Pushlet简单应用小结】 Pushlet是一种基于Java的实时数据推送技术,它允许服务器主动向客户端推送数据,而不需要...通过学习Pushlet,开发者可以更好地掌握服务器推送的概念,为构建高效的实时Web应用打下基础。

    pushlet聊天工具编辑中。。。。

    根据提供的标签“源码”和“工具”,我们可以推断这个压缩包可能包含了一个聊天工具的源代码,用于帮助开发者理解和学习如何构建类似的应用。由于描述中提到的博文链接已失效,无法直接获取详细开发过程,但我可以为...

    pushlet2.0.2

    开发者可以通过解压文件,阅读文档,运行示例来学习如何在自己的项目中使用Pushlet2.0.2进行服务器推送。 总的来说,Pushlet2.0.2是一个强大的工具,对于需要实现实时数据交换的Web应用程序开发者来说,它提供了一...

    pushlet java 消息实时推送

    通过分析这个项目源码,我们可以深入理解Pushlet的工作原理,学习如何在Java中实现消息推送,并解决实际应用中的中文字符处理问题。 总的来说,Pushlet Java 消息实时推送实例是一个很好的学习资源,它不仅展示了...

    开源框架Pushlet入门(转)

    学习Pushlet有助于开发者了解Web推送的基本原理,为后续学习更现代的推送技术打下基础。通过阅读源码,开发者还可以深入理解HTTP、Servlet和事件驱动编程的细节。在实际项目中,可以根据需求选择适合的推送解决方案...

    pushlet 资料

    总的来说,Pushlet是早期实现服务器向客户端实时推送数据的一种解决方案,虽然现在可能已经被其他技术所取代,但它在当时的Web开发中起到了重要的作用,对于理解实时通信机制仍然具有一定的学习价值。

    Ext demopushlet + Extjs 聊天室v0.9 (含源码)

    【标题】"Ext demopushlet + Extjs 聊天室v0.9 (含源码)" 是一个基于Web的实时聊天应用示例,它整合了Pushlet技术和ExtJS库,提供了完整的源代码供开发者学习和参考。Pushlet是一种推送技术,用于实现实时数据从...

Global site tag (gtag.js) - Google Analytics