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. JAVA - Annotation 注解 入门

    Java注解提供了关于代码的一些信息,但并不直接作用于它所注解的代码内容.在这个教程当中,我们将学习Java的注解,如何定制注解,注解的使用以及如何通过反射解析注解. Java1.5引入了注解,当前许 ...

  2. java,编写一个从1循环到150并在每行打印一个值,另外在每个3的倍数行上打印出foo,在每个5的倍数行上打印biz,在每个7的倍数上打印baz.

    需求:编写一个从1循环到150并在每行打印一个值,另外在每个3的倍数行上打印出foo,在每个5的倍数行上打印biz,在每个7的倍数上打印baz. package study01; public cla ...

  3. python中的sort、sorted排序

    我们通常会遇到对数据库中的数据进行排序的问题,今天学习一下对列表和字典的排序方法. 列表 第一种:内建方法sort sort()对列表排序是永久性的排序. 用法:sort(*, key=None, r ...

  4. jQuery 淡入淡出有png图的时候 ie8下有黑色边框

    jQuery fadeTo 时ie8 png图片有黑色边框 往带有png图的样式里加 filter:progid:DXImageTransform.Microsoft.AlphaImageLoader ...

  5. 【linux】【CPU】【x86】平台说明

    节选自 <鸟哥的linux私房菜> http://cn.linux.vbird.org/linux_basic/0520rpm_and_srpm_1.php 操作硬件平台:这是个很好玩的地 ...

  6. python导出开发环境

    1.导出开发环境的依赖包 本地开发完后,再把代码给别人之前,需要 pip freeze > pip123.txt 2.其他环境安装依赖包 pip install -r pip123.txt 其他 ...

  7. golang 函数的特殊用法

    1.可以复用一些写法.经常在单元测试过程中需要new一些对象可以new的操作抽离出来 package main import "fmt" type S struct { } fun ...

  8. Python使用gevent实现协程

    Python中多任务的实现可以使用进程和线程,也可以使用协程. 一.协程介绍 协程,又称微线程.英文名Coroutine.协程是Python语言中所特有的,在其他语言中没有. 协程是python中另外 ...

  9. urlopen SSL证书验证

    错误描述: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:777) 解决方法 ...

  10. Linux学习-可唤醒停机期间的工作任务

    什么是 anacron anacron 并不是用来取代 crontab 的,anacron 存在的目的就在于我们上头提到的,在处理非 24 小 时一直启动的 Linux 系统的 crontab 的执行 ...