Pushlets是在类名为Pushlet的servlet的init方法中进行初始化的。一般我们会在web.xml配置pushlet的时候,指定其servlet在Web应用启动时就进行初始化,即便这样,还是有可能初始化失败,导致整个Pushlets失效。Pushlet.init代码如下:

 public void init()
throws ServletException
{
try
{
String webInfPath = getServletContext().getRealPath("/") + "/WEB-INF";
Config.load(webInfPath); Log.init(); Log.info("init() Pushlet Webapp - version=" + Version.SOFTWARE_VERSION + " built=" + Version.BUILD_DATE); SessionManager.getInstance().start(); Dispatcher.getInstance().start(); if (Config.getBoolProperty("sources.activate"))
EventSourceManager.start(webInfPath);
else
Log.info("Not starting local event sources");
}
catch (Throwable t) {
throw new ServletException("Failed to initialize Pushlet framework " + t, t);
}
}

Pushlet.init()源代码

Pushlet类的初始化方法首先会加载Pushlets配置和日志打印组件。其首先调用的Config.load()方法会在class path及WEB-INF中查找pushlet.properties配置文件,并加载所有配置项。这一步至关重要,因为Pushlet会根据配置项决定如何实例化controller、dispatcher、session manager、session、subscriber、subscription这些核心类以及日志类,默认的配置指向这些类的默认实现。事实上,Pushlets正是通过pushlet配置文件来实现其扩展性和灵活性的。如果Pushlets的默认实现无法满足你的业务要求,你可以添加自己的实现,只要继承自Pushlet默认的实现,然后重写其中的某个方法即可。

举个例子,如果要实现Pushlet点对点推送消息,需要知道被推送的对象,因而需要“固定”住Pushlet产生的pushlet session id(有别于web的session id,是有pushlet自己产生和维护的,默认的实现是一串随机字符串),在网上搜索的有些实现是直接修改Pushlets的源代码直接改写SessionManager的createSession来生成跟用户ID强绑定的pushlet session id,例如直接使用用户ID作为pushlet session id,实际上不需要修改Pushlets的源码这么暴力,可以继承SessionManager实现自己的MySessionManager并重写createSessionId方法来返回用户ID,然后在pushlet.properties配置文件中将sessionmanager.class=nl.justobjects.pushlet.core.SessionManager配置项改写为我们自己的实现例如com.test.MySessionManager。这样的实现方式可以比较好的将我们自己的业务代码与开源组件的代码分离,至少在Pushlets.jar版本升级的时候(为了使用新功能或修复bug),能够省去不少合并代码的麻烦。

回头来说Pushlets的初始化陷阱,Dispatcher提供broadcast、multicast、unicast来进行消息的广播、多播和单播,这都会调用到SessionManager类。而Dispatcher和SessionManager都是单例实现,通过getInstance来获取自身对象的引用,它是采用一段静态代码来实现单例创建的,SessionManager的实例化代码如下

  static
{
try
{
instance = (SessionManager)Config.getClass("sessionmanager.class", "nl.justobjects.pushlet.core.SessionManager").newInstance();
Log.info("SessionManager created className=" + instance.getClass());
} catch (Throwable t) {
Log.fatal("Cannot instantiate SessionManager from config", t);
}
}

这段代码只会在程序第一次引用SessionManager时执行一次,如果我们的业务代码在调用Dispatcher类的相应方法执行消息推送(不管是广播、多播还是单播)的时候,系统尚未调用Pushlet.init方法初始化Pushlets,那么就会因为配置尚未加载而造成instance对象创建失败,其后整个Pushlets都是瘫痪的,虽然应用程序能够成功启动,但消息推送的功能就是失效的。例如,我们采用Spring框架的时候,一般是配置org.springframework.web.context.ContextLoaderListener来装载Spring框架,这样一来Spring框架会在Pushlet servlet之前初始化完成。在这个空挡如果业务逻辑触发了Pushlets消息推送,就将导致Dispatcher、SessionManager类的静态代码块被执行。虽然随后Pushlet.init方法会加载配置项,但关于如何创建核心类实例的配置项将不会再被使用。

Pushlets的初始化陷阱的更多相关文章

  1. init/main.c

    /* * linux/init/main.c * * Copyright (C) 1991, 1992 Linus Torvalds */ #include <stdarg.h> #inc ...

  2. Java编程陷阱-类成员初始化

    原文地址:http://blog.csdn.net/veryitman/article/details/6450523 如果你忽略Java的细节,恐怕你的代码会充满bug,下面讨论关于类成员初始化问题 ...

  3. [转]在static代码块或static变量的初始化过程中使用ServiceManager提供的api的陷阱

    一. 案例 1.源码: /** @hide */ private TelephonyManager(int slotId) { mContext = null; mSlotId = slotId; i ...

  4. [golang 易犯错误] golang 局部变量初始化:=的陷阱

    我们知道,golang中局部变量初始化方法(使用“:=”创建并赋值),让我们在使用变量时很方便.但是,这也是易犯错误的地方之一.特别是这个初始化符还支持多个变量同时初始化,更特别的是它还支持原有变量赋 ...

  5. Java 构造时成员初始化的陷阱

    1.首先列出代码 Base.java public class Base { Base() { preProcess(); } void preProcess() {} } Derived.java ...

  6. JAVA构造时成员初始化的陷阱

    让我们先来看两个类:Base和Derived类.注意其中的whenAmISet成员变量,和方法preProcess(). 情景1:(子类无构造方法) class Base { Base() { pre ...

  7. NSFileManager在初始化文件的时候一不留神就进入陷阱

    今天调试一个程序,内容是在手机一个本地路径生成一个缓存文件,在生成本地路径的时候犯了一个错误,本着求原因的精神调试了2个小时,终于找到原因了 刚开始断点调试的时候,执行到第13行,这里死活不给写入数据 ...

  8. 洛谷P1156 垃圾陷阱[背包DP]

    题目描述 卡门――农夫约翰极其珍视的一条Holsteins奶牛――已经落了到“垃圾井”中.“垃圾井”是农夫们扔垃圾的地方,它的深度为D(2<=D<=100)英尺. 卡门想把垃圾堆起来,等到 ...

  9. java中类的初始化和对象的初始化

    静态的属于全局静态区,这个部分独立存在,不管是成员还是块,都是静态的,大家地位相等,先到先得. 然后是成员初始化,这个部分在类的构造函数前初始化,因为编译器(或者设计者)可能认为构造函数调用了这个成员 ...

随机推荐

  1. JavaScript无提示关闭当前页面窗口,兼容IE/Firefox/Chrome

    <script type="text/javascript" language="javascript"> function fc(){ var b ...

  2. VMware9虚拟机安装MAC OS X Mountain Lion 10.8.2详细图文教程

    VMware虚拟机安装Mac OS X Mountain Lion 10.8.2所需文件:1.Vmware 9.01版下载:点击进入2.Vmware 9.01版汉化文件:点击进入3.VMware Wo ...

  3. xmpp 协议详解

    XMPP(可扩展消息处理现场协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线现场探测.它在促进服务器之间的准即时操作.这个协议可能最终允许因特网用户向因特网上的其他任何人发送 ...

  4. NOIP模拟赛 抓牛

    [题目描述] 农夫约翰被通知,他的一只奶牛逃逸了!所以他决定,马上出发,尽快把那只奶牛抓回来. 他们都站在数轴上.约翰在N(O≤N≤100000)处,奶牛在K(O≤K≤100000)处.约翰有两种办法 ...

  5. React 基础知识总结

    data-id="1190000016885142" data-license=""> 一.Node.js Node.js并不是一个JavaScript框 ...

  6. 使用el-checkbox实现全选,点击失效没有反应

    最近在公司接收到了一个需求,给收藏夹的书籍添加批量.全选删除实现思路:点击全选改变item的checked,改变item的checked,重新便利一下所有item的checked来改变全选的selec ...

  7. python爬虫基础12-selenium大全6/8-等待

    Selenium笔记(6)等待 本文集链接:https://www.jianshu.com/nb/25338984 简介 在selenium操作浏览器的过程中,每一次请求url,selenium都会等 ...

  8. day14-推导式和生成器表达式

    1.推导式规则 [每一个元素或者是和元素相关的操作 for 元素 in 可迭代数据类型] ----------遍历之后挨个处理[满足条件的元素相关的操作 for 元素 in 可迭代数据类型 if 元素 ...

  9. centos7 killall 命令

    centos7精简安装后,使用中发现没有killall命令. 安装这个包即可: yum install psmisc

  10. Pond Cascade Gym - 101670B 贪心+数学

    题目:题目链接 思路:题目让求最下面池子满的时间和所有池子满的时间,首先我们考虑所有池子满的时间,我们从上到下考虑,因为某些池子满了之后溢出只能往下溢水,考虑当前池子如果注满时间最长,那么从第一个池子 ...