通常在非集群环境下,可以启动session监听器,每次会话的创建时通过全局变量记录,会话销毁时在全局变量中消除,达到存储会话信息的目的。
在集群环境下采用内存复制方式时,集群环境下服务器间进行Session同步时,监听器不执行创建、销毁方法,直接导致统计session信息不准确(各服务器只能记录本服务器的session,无法进行汇总)。
为了更精确地在集群环境下统计当前会话数及当前在线用户数,暂时看来采用session内存复制的方式无法实现,因此可以考虑变更session管理策略,将会话信息持久化到数据库中。session数据库持久化配置方法来自weblogic9.2官方文档,以oracle数据库为例,具体配置过程如下:
1.首先在数据库中建立存储session的数据表,表命名为wl_servlet_sessions,建表sql语句如下:
create table wl_servlet_sessions ( wl_id VARCHAR2(100) NOT NULL, wl_context_path VARCHAR2(100) NOT NULL, wl_is_new CHAR(1), wl_create_time NUMBER(20), wl_is_valid CHAR(1), wl_session_values LONG RAW, wl_access_time NUMBER(20), wl_max_inactive_interval INTEGER, PRIMARY KEY (wl_id, wl_context_path) );
<?xml version="1.0" encoding="UTF-8"?> <wls:weblogic-web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wls="http://www.bea.com/ns/weblogic/90" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd http://www.bea.com/ns/weblogic/90 http://www.bea.com/ns/weblogic/90/weblogic-web-app.xsd"> <wls:session-descriptor> <wls:timeout-secs>300</wls:timeout-secs> <wls:invalidation-interval-secs>60</wls:invalidation-interval-secs> <wls:persistent-store-type>jdbc</wls:persistent-store-type> <wls:persistent-store-pool>cognos</wls:persistent-store-pool> <wls:persistent-store-table>wl_servlet_sessions</wls:persistent-store-table> </wls:session-descriptor> <wls:container-descriptor> <wls:servlet-reload-check-secs>-1</wls:servlet-reload-check-secs> <wls:session-monitoring-enabled>true</wls:session-monitoring-enabled> <wls:prefer-web-inf-classes>true</wls:prefer-web-inf-classes> </wls:container-descriptor> <wls:context-root>cognos</wls:context-root> </wls:weblogic-web-app>
说明:
persistent-store-type设置为jdbc,表示采用数据库存储方式;
persistent-store-pool指定weblogic的数据源名称为cognos(可根据项目实际情况进行更改);
persistent-store-table指定session存储的表名称;其他标签就不做介绍。
context-root设置为cognos,表示当前工程的应用发布名(可根据实际情况进行更改)。
4、编写测试程序如下:
4.1、新建java类SessionDb.java,具体代码如下:
package com.olive;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.io.StreamCorruptedException;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import weblogic.common.internal.WLObjectInputStream;
import weblogic.j2ee.ApplicationManager;
import weblogic.rmi.utils.io.RemoteObjectReplacer;
import weblogic.servlet.internal.AttributeWrapper;
import weblogic.utils.StackTraceUtils;
import weblogic.utils.io.UnsyncByteArrayInputStream;
public class SessionDb {
static final Hashtable convert(Object obj) {
if (obj == null || (obj instanceof Hashtable))
return (Hashtable) obj;
Dictionary dictionary = (Dictionary) obj;
Hashtable hashtable = new Hashtable(dictionary.size());
Object obj1;
for (Enumeration enumeration = dictionary.keys(); enumeration
.hasMoreElements(); hashtable.put(obj1, dictionary.get(obj1)))
obj1 = enumeration.nextElement();
return hashtable;
}
public static Hashtable deSerializeAttributes(byte abyte0[]) throws IOException,Exception {
Hashtable ht = new Hashtable();
try {
UnsyncByteArrayInputStream unsyncbytearrayinputstream = new UnsyncByteArrayInputStream(abyte0);
if (abyte0[0] == -84 && abyte0[1] == -19) {
SessionMigrationObjectInputStream sessionmigrationobjectinputstream = new SessionMigrationObjectInputStream(
unsyncbytearrayinputstream);
add2table(ht,convert(sessionmigrationobjectinputstream.readObject()));
try {
add2table(ht,convert(sessionmigrationobjectinputstream.readObject()));
} catch (StreamCorruptedException streamcorruptedexception) {
System.out.println("ERROR:deSerializeAttributes is error!");
// internalAttributes = null;
// if(isDebugEnabled())
// DEBUG_SESSIONS.debug("Ignoring the
// StreamCorruptedException " +
// streamcorruptedexception.getMessage());
}
} else {
WLObjectInputStream wlobjectinputstream = new WLObjectInputStream(unsyncbytearrayinputstream);
wlobjectinputstream.setReplacer(RemoteObjectReplacer.getReplacer());
add2table(ht,convert(wlobjectinputstream.readObject()));
try {
add2table(ht,convert(wlobjectinputstream.readObject()));
} catch (StreamCorruptedException streamcorruptedexception1) {
// internalAttributes = null;
// if(isDebugEnabled())
// DEBUG_SESSIONS.debug("Ignoring the
// StreamCorruptedException " +
// streamcorruptedexception1.getMessage());
}
//printTable(ht);
}
} catch (ClassNotFoundException classnotfoundexception) {
throw new IOException("Exception deserializing attributes:"
+ StackTraceUtils
.throwable2StackTrace(classnotfoundexception));
}
return ht;
}
private static class SessionMigrationObjectInputStream extends ObjectInputStream {
public Class resolveClass(ObjectStreamClass objectstreamclass)throws ClassNotFoundException {
return ApplicationManager.loadClass(objectstreamclass.getName(),null);
}
public SessionMigrationObjectInputStream() throws IOException,
SecurityException {
}
public SessionMigrationObjectInputStream(
UnsyncByteArrayInputStream unsyncbytearrayinputstream)
throws IOException, StreamCorruptedException {
super(unsyncbytearrayinputstream);
}
}
public static void printTable(Hashtable p_ht) throws Exception{
Iterator _it= p_ht.entrySet().iterator();
for(;_it.hasNext();){
Map.Entry _entry = (Map.Entry) _it.next();
AttributeWrapper _value =(AttributeWrapper)_entry.getValue();
System.out.println(_entry.getKey() + "=" + _value.getObject().toString() );
}
}
private static Hashtable add2table(Hashtable p_ht,Hashtable p_ht1) throws Exception{
if(null==p_ht1) return p_ht;
Iterator _it= p_ht1.entrySet().iterator();
for(;_it.hasNext();){
Map.Entry _entry = (Map.Entry) _it.next();
AttributeWrapper _value =(AttributeWrapper)_entry.getValue();
p_ht.put(_entry.getKey(), _value.getObject() );
}
return p_ht;
}
}
说明:
deSerializeAttributes方法是该类的核心,该方法负责对wl_servlet_sessions表中存储的session信息进行反序列化,并将反序列化的结果存储到Hashtable数据结构中。
4.2、建立session数据显示jsp页面命名为session_list.jsp,代码如下:
<%@ page language="java" pageEncoding="utf-8"%>
<%@ page import="java.sql.*"%>
<%@ page import="javax.sql.*"%>
<%@ page import="java.util.*"%>
<%@ page import="javax.naming.*"%>
<%@ page import="com.olive.*"%>
<%@ page import="com.olive.security.domain.*"%>
<%@ page import="javax.servlet.http.*"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>session统计</title>
</head>
<body>
<br>
<%
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("jdbc/cognos");
Connection conn = ds.getConnection();
Statement sm = conn.createStatement();
ResultSet rs = sm.executeQuery("select * from wl_servlet_sessions");
while (rs.next()) {
System.out.println("userId:"+rs.getString(1));//用户id
byte[] _bytes = rs.getBytes("wl_session_values");
Hashtable _ht = SessionDb.deSerializeAttributes(_bytes);
%>
<hr>
<%
Iterator _it= _ht.entrySet().iterator();
for(;_it.hasNext();){
Map.Entry _entry = (Map.Entry) _it.next();
%>
<%=_entry.getKey()%>=<%= _entry.getValue()%>
<br>
<%
}
}
}
sm.close();
rs.close();
conn.close();
%>
</body>
</html>
5、按照以上步骤操作完成后,将程序打包发布到weblogic9.2上。运行程序中的功能页面,系统会建立session,然后在ie中方问题session_list.jsp页面,该页面会将系统中存在的所有会话信息在页面进行显示。