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. nodejs写一个简单的Web服务器

    目录文件如 httpFile.js如下: const httpd = require("http"); const fs = require("fs"); // ...

  2. 在VMware上安装centos7

    1. 下载centos7 64位镜像 linux官网下载:https://www.centos.org/download/ 2. 在VMware上安装centos7 2.1 新建虚拟机 打开虚拟机主页 ...

  3. spring IOC注解与xml配置

    转载自:https://blog.csdn.net/u014292162/article/details/52277756 IOC 1小案例 将对象的依赖交给配置文件来配置(配置文件的名字是可以任意的 ...

  4. 安装ElasticSearch 6.1.1 head插件

    https://blog.csdn.net/zoubf/article/details/79007908 主要参考了这个blog 才完成所有的配置,很好的参考资料

  5. PHP安装Xcache扩展

    简述 XCache 是一个又快又稳定的 ​PHP opcode 缓存器. 经过良好的测试并在大流量/高负载的生产机器上稳定运行. 经过(在 linux 上)测试并支持所有现行 ​PHP 分支的最新发布 ...

  6. 蓝牙nrf52832的架构和开发(转载)

    相比TI的CC254X.DIALOG的DA1458X,nordic推出的nrf51822和nrf52832在架构和开发商都有自己独特的地方.这几颗产品都是蓝牙低功耗芯片.DA1458X使用OTP硬件架 ...

  7. Party Games UVA - 1610 贪心

    题目:题目链接 思路:排序后处理到第一个不同的字符,贪心一下就可以了 AC代码: #include <iostream> #include <cstdio> #include ...

  8. CodeForces - 485D Maximum Value (数学)

    题意: n个数,求出这些数中满足 ai >= aj 的 ai % aj 的最大值. 排序去重,然后对于每一个a[i], 如果找到a[i] 的一个倍数 k*a[i] (k > 1)的位置,那 ...

  9. HDU 4871 Shortest-path tree 最短路 + 树分治

    题意: 输入一个带权的无向连通图 定义以顶点\(u\)为根的最短路生成树为: 树上任何点\(v\)到\(u\)的距离都是原图最短的,如果有多条最短路,取字典序最小的那条. 然后询问生成树上恰好包含\( ...

  10. 等待唤醒(wait / notify)机制

    如果一个线程从头到尾执行完也不和别的线程打交道的话,那就不会有各种安全性问题了.但是协作越来越成为社会发展的大势,一个大任务拆成若干个小任务之后,各个小任务之间可能也需要相互协作最终才能执行完整个大任 ...