通常在非集群环境下,可以启动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页面,该页面会将系统中存在的所有会话信息在页面进行显示。