Pushlets的初始化陷阱
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的初始化陷阱的更多相关文章
- init/main.c
		
/* * linux/init/main.c * * Copyright (C) 1991, 1992 Linus Torvalds */ #include <stdarg.h> #inc ...
 - Java编程陷阱-类成员初始化
		
原文地址:http://blog.csdn.net/veryitman/article/details/6450523 如果你忽略Java的细节,恐怕你的代码会充满bug,下面讨论关于类成员初始化问题 ...
 - [转]在static代码块或static变量的初始化过程中使用ServiceManager提供的api的陷阱
		
一. 案例 1.源码: /** @hide */ private TelephonyManager(int slotId) { mContext = null; mSlotId = slotId; i ...
 - [golang 易犯错误] golang 局部变量初始化:=的陷阱
		
我们知道,golang中局部变量初始化方法(使用“:=”创建并赋值),让我们在使用变量时很方便.但是,这也是易犯错误的地方之一.特别是这个初始化符还支持多个变量同时初始化,更特别的是它还支持原有变量赋 ...
 - Java 构造时成员初始化的陷阱
		
1.首先列出代码 Base.java public class Base { Base() { preProcess(); } void preProcess() {} } Derived.java ...
 - JAVA构造时成员初始化的陷阱
		
让我们先来看两个类:Base和Derived类.注意其中的whenAmISet成员变量,和方法preProcess(). 情景1:(子类无构造方法) class Base { Base() { pre ...
 - NSFileManager在初始化文件的时候一不留神就进入陷阱
		
今天调试一个程序,内容是在手机一个本地路径生成一个缓存文件,在生成本地路径的时候犯了一个错误,本着求原因的精神调试了2个小时,终于找到原因了 刚开始断点调试的时候,执行到第13行,这里死活不给写入数据 ...
 - 洛谷P1156 垃圾陷阱[背包DP]
		
题目描述 卡门――农夫约翰极其珍视的一条Holsteins奶牛――已经落了到“垃圾井”中.“垃圾井”是农夫们扔垃圾的地方,它的深度为D(2<=D<=100)英尺. 卡门想把垃圾堆起来,等到 ...
 - java中类的初始化和对象的初始化
		
静态的属于全局静态区,这个部分独立存在,不管是成员还是块,都是静态的,大家地位相等,先到先得. 然后是成员初始化,这个部分在类的构造函数前初始化,因为编译器(或者设计者)可能认为构造函数调用了这个成员 ...
 
随机推荐
- 远程连接 mySql数据库
			
远程连接 mySql数据库 一.安装并配置MySQL1.安装MySQL:运行mysql-essential-6.0.11-alpha-win32,按“MySQL+6.0+Windows下安装图解”完成 ...
 - Unicode与ASCiI之间有什么区别?java当中的转义字符 Character类的使用 String类的使用
			
ASCII码 称为 美国标准信息交换码 (American standard code of Information Interchange) 其中一共有多少个码?2的7次幂 128个 Unicode ...
 - thinkcmf5 模板版变量的加载过程 和 新增网站配置项怎么全局使用
			
1.模板全局配置是怎么加载的 在 HomeBaseController.php 的 fech方法 $more = $this->getThemeFileMore($template); ...
 - MYSQL导入数据:Table XXX doesn't exist的解决
			
数据表为Innodb引擎 data文件夹中存在数据表的frm文件,但在phpmyadmin中看不到这些表,于是采用导入sql文件的方式进行恢复 1.直接导入原数据表的sql文件,原frm文件不删除 出 ...
 - redis代理集群(Twemproxy)(1)
			
redis主从+哨兵模式只解决了读的分布式操作,大大提高了性能:但是写操作,只有主主机器才能进行,从机器无法进行写操作.此时,Twemproxy也就出现了. 这个模式单纯的安装有些复杂,需要引入很多的 ...
 - LeetCode(151) Reverse Words in a String
			
题目 Given an input string, reverse the string word by word. For example, Given s = "the sky is b ...
 - Linux学习-核心的编译与安装
			
编译核心与核心模块 核心与核心模块需要先编译起来,而编译的过程其实非常简单,你可以先使用『 make help 』去查 阅一下所有可用编译参数, 就会知道有底下这些基本功能: [root@study ...
 - 持续化集成Jenkins的系统配置
			
最近在研究selenium2自动化测试,用到持续化集成jenkins.由于之前仅限于使用,而没有真正动手配置过,所以现在学习从零开始,搭建持续化集成,故而有了这篇博客. 先介绍一下项目持续集成测试,这 ...
 - Prolog&Epilog
			
这篇博客会简单介绍一下Prolog&Epilog 然后再简单介绍下我对于程序在计算机中到底如何运行的一些理解(因为自己之前也从来没有接触过这些方面的知识,所以如果有讲的不对的地方希望大家能够帮 ...
 - LA 7048 Coprime 莫比乌斯反演
			
题意: 给出\(n(n \leq 10^5)\)个数字\(a_i(a_i \leq 10^5)\),从中选出\(3\)个数,使得这\(3\)个数两两互质或者两两不互质 分析: 可以说这是<训练指 ...