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. C++ 学习笔记(二) const的加强

    const 含义为只读.如果在程序中显式改变const变量那么编译会报错. C语言的const: 在C语言中const 变量是放在内存中,如果使用指针可以间接改变const变量.所以在C语言中cons ...

  2. java实现可安装的exe程序

    java实现可安装的exe程序 通过编写Java代码,实现可安装的exe文件的一般思路: 1.在eclipse中创建java项目,然后编写Java代码,将编写好的Java项目导出一个.jar格式的ja ...

  3. Linux系统修改网卡名(eth0-3)

    一.命名规则策略 规则1: 对于板载设备命名合并固件或 BIOS 提供的索引号,如果来自固件或 BIOS 的信息可读就命名,比如eno1,这种命名是比较常见的,否则使用规则2. 规则2: 命名合并固件 ...

  4. 【markdown】图片的处理

    1st: ![tip](link) 2ed: ![tip][id] [id]:base64string 本地图片 先把本地图片文件转换成base64位编码 然后把 link 替换成生成的base64编 ...

  5. MySQL迁移升级解决方案

    任务背景 由于现有业务架构已不能满足当前业务需求,在保证数据完整的前提下,现需要将原有数据库迁移到另外一台单独的服务器上,在保证原有服务正常的情况下,将原有LAMP环境中mysql数据库版本5.6.3 ...

  6. Altium Designer入门学习笔记1.软件安装与资料收集

    一.软件安装 微信:http://url.cn/5Eudzt9 关注微信公众号"软件安装管家",点击"软件目录",弹出"软件目录",点击进入 ...

  7. Tomcat Bug记录

    1.问题:org.apache.tiles.request.render.CannotRenderException: ServletException including path '/WEB-IN ...

  8. how to setting a i2c driver

    How to instantiate I2C devices============================== Unlike PCI or USB devices, I2C devices ...

  9. Aizu - 1386 Starting a Scenic Railroad Service (思维乱搞)

    给你n个区间,求: 1:最多有多少区间与同一个区间相交. 2:相交部分的最大区间数目. Sample Input 1 4 1 3 1 3 3 6 3 6 Sample Output 1 2 2 Sam ...

  10. kettle-批量同步表数据

    一.实验目标 利用kettle实现从mysql数据库中的dbf库批量同步表到dbm库(全量同步) 二.实验环境 dbf  库中表f1.f2.f3  .f1中1条数据,f2中100条数据,f3中2条数据 ...