设为首页 收藏本站
查看: 391|回复: 0

[经验分享] tomcat session——对session的支持

[复制链接]

尚未签到

发表于 2017-1-30 07:20:39 | 显示全部楼层 |阅读模式
  一,tomcat 如何支持session
  首先来看下$catalina.home/conf/context.xml

<Context>
<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
<!-- Uncomment this to enable Comet connection tacking (provides events
on session expiration as well as webapp lifecycle) -->
<!--
<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
-->
<Manager className="org.apache.catalina.session.PersistentManager" checkInterval="1" maxIdleBackup="2">
<Store className="org.apache.catalina.session.JDBCStore" driverName="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/session?user=root&amp;password=hello"
sessionTable="session" sessionIdCol="session_id" sessionDataCol="session_data"
sessionValidCol="sessionValid" sessionMaxInactiveCol="maxInactive"
sessionLastAccessedCol="lastAccess" sessionAppCol="appName" checkInterval="1" debug="99" />
</Manager>
</Context>
  众所周知 HTTP协议是说HTTP是无状态的,而我们常常使得程序有状态无非一种办法,把相同会话(即一组应当有状态的请求)都赋予一个统一的标识即JSESSIONID。
  如果每次请求过来都带有JSESSIONID的话,那么这些请求都可以看成是同一个会话下的,那么会话中的状态就可以再服务端内存或者任何地方进行保存和关联。
  1,那么这个JSESSIONID,首先是服务端生成的一个唯一标示(TOMCAT内部实现会帮我们自动生成)
  2,其次这个JSESSIONID会被传给客户端。传给客户端有两种方式:
  A,写到客户端Cookie里去。B,给客户端进行URL 的rewriter。
  所以客户端拿到这个JSESSIONID之后再提交给服务端的时候,服务端就能知道:哦,原来你就是上次来请求过我的那个人;我记得你在我这边喝了一杯咖啡还没付钱呢。
  那么JSESSIONID从服务端写到客户端有两个步骤,A和B,服务端是如何选择用哪种方式的呢。这里就看上面贴出来的XML配置
  如果 <Context cookies="false"> 那么是禁用了cookie的,表示用url rewriter的方式
  否则默认都是用cookie的方式保存JSESSIONID的。
  ================ 上面讲了 服务器如何生成JSESSIONID,并且把Cookie保存到客户端 ===========
  ================ 下面讲服务器如何保存JSESSIONID,即会话状态 ===========
  服务器保存会话有两种方式:
  1,标准方式,就保存到内存里。系统一旦shutdown,全部会话忘了。你欠我一杯咖啡也忘了。
  2,持久化保存,使得系统重启可恢复
  如我上面贴出来的配置

  <Manager className="org.apache.catalina.session.PersistentManager" checkInterval="1" maxIdleBackup="2">
  <Store className="org.apache.catalina.session.JDBCStore" driverName="com.mysql.jdbc.Driver"
   connectionURL="jdbc:mysql://localhost:3306/session?user=root&amp;password=hello"
   sessionTable="session" sessionIdCol="session_id" sessionDataCol="session_data"
   sessionValidCol="sessionValid" sessionMaxInactiveCol="maxInactive"
   sessionLastAccessedCol="lastAccess" sessionAppCol="appName" checkInterval="1" debug="99" />
 </Manager>
  当系统被正常关闭的时候,内存中的session会被保存到数据库里。
  如图:

DSC0000.png

  当然这里得先建好数据库。
  类似:


create table tomcat_sessions (
session_id     varchar(100) not null primary key,
valid_session  char(1) not null,
max_inactive   int not null,
last_access    bigint not null,
app_name       varchar(255),
session_data   mediumblob,
KEY kapp_name(app_name)
);



  其中 maxIdleBackup 代表这个session 空闲了多少秒就会被保存到数据库里。
  详细配置参见官网:
  http://tomcat.apache.org/tomcat-4.1-doc/config/manager.html

  ========================= 邪恶的分割线 ======================
  二,tomcat 如何产生 一个新的session
  MangerBase.java

    /**
* Construct and return a new session object, based on the default
* settings specified by this Manager's properties.  The session
* id specified will be used as the session id.  
* If a new session cannot be created for any reason, return
* <code>null</code>.
*
* @param sessionId The session id which should be used to create the
*  new session; if <code>null</code>, a new session id will be
*  generated
* @exception IllegalStateException if a new session cannot be
*  instantiated for any reason
*/
public Session createSession(String sessionId) {
// Recycle or create a Session instance
Session session = createEmptySession();
// Initialize the properties of the new session and return it
session.setNew(true);
session.setValid(true);
session.setCreationTime(System.currentTimeMillis());
session.setMaxInactiveInterval(this.maxInactiveInterval);
if (sessionId == null) {
sessionId = generateSessionId();
}
session.setId(sessionId);
sessionCounter++;
return (session);
}
  真正生成JSESSIONID的实现:

  /**
* Generate and return a new session identifier.
*/
protected synchronized String generateSessionId() {
byte random[] = new byte[16];
String jvmRoute = getJvmRoute();
String result = null;
// Render the result as a String of hexadecimal digits
StringBuffer buffer = new StringBuffer();
do {
int resultLenBytes = 0;
if (result != null) {
buffer = new StringBuffer();
duplicates++;
}
while (resultLenBytes < this.sessionIdLength) {
getRandomBytes(random);
random = getDigest().digest(random);
for (int j = 0;
j < random.length && resultLenBytes < this.sessionIdLength;
j++) {
byte b1 = (byte) ((random[j] & 0xf0) >> 4);
byte b2 = (byte) (random[j] & 0x0f);
if (b1 < 10)
buffer.append((char) ('0' + b1));
else
buffer.append((char) ('A' + (b1 - 10)));
if (b2 < 10)
buffer.append((char) ('0' + b2));
else
buffer.append((char) ('A' + (b2 - 10)));
resultLenBytes++;
}
}
if (jvmRoute != null) {
buffer.append('.').append(jvmRoute);
}
result = buffer.toString();
} while (sessions.containsKey(result));
return (result);
}
  当然上面那个MangerBase是个抽象类,他有各种子类:
  比如:DeltaManager.java实现了分布式集群中session的拷贝。

/**
* create new session with check maxActiveSessions and send session creation
* to other cluster nodes.
*
* @param distribute
* @return The session
*/
public Session createSession(String sessionId, boolean distribute) {
if ((maxActiveSessions >= 0) && (sessions.size() >= maxActiveSessions)) {
rejectedSessions++;
throw new IllegalStateException(sm.getString("deltaManager.createSession.ise"));
}
DeltaSession session = (DeltaSession) super.createSession(sessionId) ;
if (distribute) {
sendCreateSession(session.getId(), session);//拷贝到集群其他机器
}
if (log.isDebugEnabled())
log.debug(sm.getString("deltaManager.createSession.newSession",session.getId(), new Integer(sessions.size())));
return (session);
}
  当然我们可以有我们自己的实现把session放到 memcached或者数据库里来解决集群问题。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-335084-1-1.html 上篇帖子: 在tomcat端配置数据池 下篇帖子: 在tomcat中部署web项目
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表