lt;深入剖析Tomcat>这本书怎么样

下次自动登录
现在的位置:
& 综合 & 正文
深入剖析Tomcat会话机制
Tomcat默认将Session保存到内存中。但同时,Tomcat也提供了PersistentManager配合不同的Store实现的方式,使Session可以被保存到不同地方(Database,Redis,Memcached等)。
例如下面的配置:
&ManagerclassName="org.apache.catalina.session.PersistentManager"
saveOnRestart="true"
maxActiveSession="-1"
minIdleSwap="0"
maxIdleSwap="0"
maxIdleBackup="-1"&
&StoreclassName="com.cdai.test.RedisStore" host="192.168.1.1"port="6379"/&
&/Manager&
通过PersistentManager配合RedisStore,实现了Session存储到Redis中。但要注意的是:切换Manager和Store实现都不会让Session全部保存到其他位置。
Tomcat只是在下面三种情况会将Session通过Store保存起来:
当Session的空闲时间超过minIdleSwap和maxIdleSwap时,会将Session换出
当Session的空闲时间超过maxIdleBackup时,会将Session备份出去
当Session总数大于maxActiveSession时,会将超出部分的空闲Session换出
所以只是简单地切换Manager和Store的实现,并不能使Tomcat把Session都保存到我们想要的地方。Tomcat还是会把内存当做Session的主存储器,我们配置的Store只是作为辅助存储器。 下面先来深入研究下Tomcat源码来研究下Session管理机制,最后我们再看下如何能达到我们想要的效果。
2.1使用Session
下面以一个使用Session的Servlet为切入点,开始分析Tomcat源码。
public class LoginServletextends HttpServlet {
private static int i = 0;
protected void service(HttpServletRequestreq, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session =req.getSession(true);
System.out.println(session.getAttribute("cdai"));
session.setAttribute("cdai","helloworld" + i++);
默认配置下,我们通过HttpServletRequest得到的HttpSession实现是StandardSession。设置属性时,只是把属性值保存到StandardSession的一个Map中。
2.2后台线程
在Tomcat 6中所有后台线程的调度都是在ContainerBase.backgroundProcess()中统一处理的。
public void backgroundProcess() {
if (!started)
if (cluster != null) {
cluster.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.cluster",cluster), e);
if (loader != null) {
loader.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.loader",loader), e);
if (manager != null) {
manager.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.manager",manager), e);
if (realm != null) {
realm.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.realm",realm), e);
Valve current = pipeline.getFirst();
while (current != null) {
current.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.valve",current), e);
current = current.getNext();
lifecycle.fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
上面源码中我们关心的是manager.backgroundProcess()一行,这是Manager后台处理的入口。
先来看下Manager的类关系:
ManagerBase 实现了Manager接口的backgroundProcess()方法。在ManagerBase.backgroundProcess()中调用子类PersistentManagerBase.processExpire()。在processExpire()中会对前面提到的Session被持久化的三种情况进行处理。下面就来看下这三种情况的源码。
2.3换出和备份
先以情况1换出空闲时间过长的Session的源码为例。
protected void processMaxIdleSwaps() {
if (!isStarted() || maxIdleSwap & 0)
Session sessions[] = findSessions();
long timeNow =System.currentTimeMillis();
// Swap out all sessions idle longerthan maxIdleSwap
if (maxIdleSwap &= 0) {
for (int i = 0; i &sessions. i++) {
StandardSession session =(StandardSession) sessions[i];
synchronized (session) {
if (!session.isValid())
int timeIdle = // Truncate,do not round up
(int) ((timeNow -session.getLastAccessedTime()) / 1000L);
if (timeIdle & maxIdleSwap && timeIdle& minIdleSwap) {
if (session.accessCount!= null &&
session.accessCount.get() & 0) {
// Session iscurrently being accessed - skip it
if(log.isDebugEnabled())
log.debug(sm.getString
("persistentManager.swapMaxIdle",
session.getIdInternal(), newInteger(timeIdle)));
swapOut(session);
} catch (IOException e){
// This is logged in writeSession()
protected void swapOut(Session session)throws IOException {
if (store == null ||!session.isValid()) {
((StandardSession)session).passivate();
writeSession(session);
super.remove(session);
session.recycle();
protected void writeSession(Sessionsession) throws IOException {
if (store == null || !session.isValid()){
if(SecurityUtil.isPackageProtectionEnabled()){
AccessController.doPrivileged(newPrivilegedStoreSave(session));
}catch(PrivilegedActionExceptionex){
Exception exception =ex.getException();
log.error("Exceptionin the Store during writeSession: "
+ exception);
exception.printStackTrace();
store.save(session);
} catch (IOException e) {
log.error(sm.getString
("persistentManager.serializeError",session.getIdInternal(), e));
private class PrivilegedStoreSave implementsPrivilegedExceptionAction {
PrivilegedStoreSave(Session session){
this.session =
public Object run() throws Exception{
store.save(session);
processMaxIdleSwaps()会将每个Session的空闲时间与minIdleSwap和maxIdleSwap比较,然后调用swapOut()将Session换出。在swapOut()中,通过PrivilegedStoreSave类调用store的save()方法将session保存到不同的地方。
另外两种情况的处理与processMaxIdleSwaps()类似。处理方法为:processMaxIdleBackups()和processMaxActiveSwaps()。
3.1简单方案
一种简单方法是依旧使用Tomcat提供的PersistentManager,自己实现Store类。之后通过调整Manager参数让Tomcat尽快把Session换出,例如开篇那段配置中,将min/maxIdleSwap设置为0。这种方法的缺点是Servlet设置Session属性,并且请求结束后,可能很大延迟后Session才会被换出。
3.2最终方案
下面来看下开源tomcat-redis-session-manager实现的源码,分析一下如何能完美切换。
这是tomcat-redis-session-manager官方提供的配置:
&ValveclassName="com.radiadesign.catalina.session.RedisSessionHandlerValve"/&
&ManagerclassName="com.radiadesign.catalina.session.RedisSessionManager"
host="localhost" &!-- optional: defaults to"localhost" --&
port="6379" &!-- optional: defaults to "6379"--&
database="0" &!-- optional: defaults to "0"--&
maxInactiveInterval="60" &!-- optional: defaults to"60" (in seconds) --& /&
可以看到除了自定义了Manager,它还提供了一个Valve实现。在Tomcat中,请求被Servlet处理前是要经过管道中的许多Valve对象处理的,类似于Struts2中的Interceptor。
public classRedisSessionHandlerValve extends ValveBase {
private final Log log =LogFactory.getLog(RedisSessionManager.class);
private RedisSessionM
public voidsetRedisSessionManager(RedisSessionManager manager) {
this.manager =
public void invoke(Request request, Responseresponse) throws IOException, ServletException {
getNext().invoke(request, response);
} finally {
final Session session =request.getSessionInternal(false);
storeOrRemoveSession(session);
manager.afterRequest();
private void storeOrRemoveSession(Sessionsession) {
if (session != null) {
if (session.isValid()) {
log.trace("Request with sessioncompleted, saving session " + session.getId());
if (session.getSession() != null) {
log.trace("HTTP Sessionpresent, saving " + session.getId());
manager.save(session);
log.trace("No HTTP Sessionpresent, Not saving " + session.getId());
log.trace("HTTP Session has beeninvalidated, removing :" + session.getId());
manager.remove(session);
} catch (Exception e) {
// Do nothing.
RedisSessionHandlerValve的处理逻辑很简单:调用getNext().invoke(request,response)使后续Valve继续处理请求。在storeOrRemoveSession()中直接调用manager.save(),而不是像之前等待Tomcat调度。
RedisSessionManager.save()实现也很简单,将Session序列化后使用Jedis保存到Redis中。
public void save(Session session) throwsIOException {
Jedis jedis =
Boolean error =
log.trace("Saving session " +session + " into Redis");
RedisSession redisSession =(RedisSession)
if (log.isTraceEnabled()) {
log.trace("Session Contents[" + redisSession.getId() + "]:");
Enumeration en =redisSession.getAttributeNames();
while(en.hasMoreElements()) {
log.trace("
" + en.nextElement());
Boolean sessionIsDirty =redisSession.isDirty();
redisSession.resetDirtyTracking();
byte[] binaryId =redisSession.getId().getBytes();
jedis = acquireConnection();
Boolean isCurrentSessionPersisted =this.currentSessionIsPersisted.get();
if (sessionIsDirty ||(isCurrentSessionPersisted == null || !isCurrentSessionPersisted)) {
jedis.set(binaryId, serializer.serializeFrom(redisSession));
currentSessionIsPersisted.set(true);
log.trace("Setting expire timeout onsession [" + redisSession.getId() + "] to " +getMaxInactiveInterval());
jedis.expire(binaryId,getMaxInactiveInterval());
} catch (IOException e) {
log.error(e.getMessage());
} finally {
if (jedis != null) {
returnConnection(jedis, error);
1 tomcat-redis-session-manager官网
2《深入剖析Tomcat》
&&&&推荐文章:
【上篇】【下篇】Java1234官方群20:
Java1234官方群20:
深入剖析Tomcat(中文版)PDF 下载
深入剖析Tomcat(中文版)PDF 下载
提醒:假如百度云分享链接失效,请联系站长,我会补上的。
深入剖析Tomcat(中文版)PDF 下载
转载自:http://download.csdn.net/detail/qq_5792
本站整理下载:链接: 密码:ovas
相关截图:
(责任编辑:小锋)
------分隔线----------------------------
《了不起的Node.js: 将JavaScript进行到底》PDF 下载...
《Java RESTful Web Service实战》PDF 下载...
《架构探险从零开始写JavaWeb框架》PDF 下载...
《疯狂Workflow讲义——基于Activiti的工作流应用开发》PDF 下载...
《Oracle WebLogic Server开发权威指南》PDF 下载...
《深入理解OSGi:Equinox原理、应用与最佳实践》PDF 下载...
免责声明:网站所有作品均由会员网上搜集共同更新,仅供读者预览及学习交流使用,下载后请24小时内删除,如果喜欢请购买正版资源!原作者如果认为本站侵犯了您的版权,请QQ告知,我们会立即删除!2014年7月 Java大版内专家分月排行榜第二
2015年1月 Java大版内专家分月排行榜第三2014年8月 Java大版内专家分月排行榜第三
2013年10月 总版技术专家分月排行榜第三
2014年3月 Java大版内专家分月排行榜第一2014年1月 Java大版内专家分月排行榜第一2013年12月 Java大版内专家分月排行榜第一2013年11月 Java大版内专家分月排行榜第一2013年10月 Java大版内专家分月排行榜第一
本帖子已过去太久远了,不再提供回复功能。2545人阅读
& 在上一节的介绍中我们学会了如何安装oracle数据库的操作,那么这一节我们先简单在DOS命令中使用oracle的命令完成一些基本的操作,希望你有所得
上内容归redarmy_chen总结创建,如需转载请添加出处,如有疑问请发送到redarmy_
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1872932次
积分:16569
积分:16569
排名:第601名
原创:209篇
转载:76篇
评论:703条
(1)(7)(1)(1)(2)(3)(1)(4)(14)(2)(2)(1)(5)(2)(1)(1)(9)(2)(2)(12)(13)(28)(6)(8)(46)(1)(1)(23)(27)(5)(2)(28)(10)(3)(2)(9)

我要回帖

更多关于 lt p gt 的文章

 

随机推荐