在weblogic9.2集群环境下准确统计当前会话数及在线用户数

      通常在非集群环境下,可以启动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) ); 

 2、在weblogic下建立数据源命名为cognos,并将该数据源指定到wl_servlet_sessions表所在的数据库。(weblogic9.2建立数据源方式参见官方文档)
 3、在WEB-INF目录下新建weblogic.xml文件,具体内容如下:
  
 <?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页面,该页面会将系统中存在的所有会话信息在页面进行显示。

你可能感兴趣的:(sql,Web,weblogic,jdbc,servlet)