(Session机制原理,如果有疑问,可查找相关文献。有个博客写的也挺实用的http://justsee.iteye.com/blog/1570652)
本人实用的Tomcat版本为5.0.28,以下内容都是针对此版本。
产生sessionId的类是,org.apache.catalina.session.StandardManager extends ManagerBase,代码实现就在ManagerBase.generateSessionId。
org.apache.catalina.session.ManagerBase是一个抽象类,为了方便直接进入主题,我对该类对了一些删减,只保留了方法generateSessionId相关的东东。
下面的就是我裁剪后的代码。
/*
* Copyright 1999,2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.session;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
/**
* Minimal implementation of the <b>Manager</b> interface that supports
* no session persistence or distributable capabilities. This class may
* be subclassed to create more sophisticated Manager implementations.
*
* @author Craig R. McClanahan
* @version $Revision: 1.27 $ $Date: 2004/05/26 16:13:59 $
*/
public class ManagerBaseTest {
// ----------------------------------------------------- Instance Variables
/**
* The default message digest algorithm to use if we cannot use
* the requested one.
*/
private static final String DEFAULT_ALGORITHM = "MD5";
/**
* The message digest algorithm to be used when generating session
* identifiers. This must be an algorithm supported by the
* <code>java.security.MessageDigest</code> class on your platform.
*/
private String algorithm = DEFAULT_ALGORITHM;
/**
* Return the MessageDigest implementation to be used when
* creating session identifiers.
*/
private MessageDigest digest = null;
/**
* A String initialization parameter used to increase the entropy of
* the initialization of our random number generator.
*/
private String entropy = null;
/**
* The session id length of Sessions created by this Manager.
*/
private int sessionIdLength = 16;
/**
* A random number generator to use when generating session identifiers.
*/
private Random random = null;
/**
* The Java class name of the random number generator class to be used
* when generating session identifiers.
*/
private String randomClass = "java.security.SecureRandom";
// ------------------------------------------------------------- Properties
/**
* Return the entropy increaser value, or compute a semi-useful value
* if this String has not yet been set.
*/
public String getEntropy() {
// Calculate a semi-useful value if this has not been set
if (this.entropy == null)
setEntropy(this.toString());
return (this.entropy);
}
/**
* Set the entropy increaser value.
*
* @param entropy The new entropy increaser value
*/
public void setEntropy(String entropy) {
this.entropy = entropy;
}
/**
* Return the MessageDigest object to be used for calculating
* session identifiers. If none has been created yet, initialize
* one the first time this method is called.
*/
public synchronized MessageDigest getDigest() {
if (this.digest == null) {
long t1=System.currentTimeMillis();
try {
this.digest = MessageDigest.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
try {
this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
} catch (NoSuchAlgorithmException f) {
this.digest = null;
}
}
long t2=System.currentTimeMillis();
}
return (this.digest);
}
/**
* Return the random number generator instance we should use for
* generating session identifiers. If there is no such generator
* currently defined, construct and seed a new one.
*/
public synchronized Random getRandom() {
if (this.random == null) {
synchronized (this) {
if (this.random == null) {
// Calculate the new random number generator seed
long seed = System.currentTimeMillis();
long t1 = seed;
char entropy[] = getEntropy().toCharArray();
for (int i = 0; i < entropy.length; i++) {
long update = ((byte) entropy[i]) << ((i % 8) * 8);
seed ^= update;
}
try {
// Construct and seed a new random number generator
Class clazz = Class.forName(randomClass);
this.random = (Random) clazz.newInstance();
this.random.setSeed(seed);
} catch (Exception e) {
// Fall back to the simple case
this.random = new java.util.Random();
this.random.setSeed(seed);
}
long t2=System.currentTimeMillis();
}
}
}
return (this.random);
}
protected void getRandomBytes( byte bytes[] ) {
Random random = getRandom();
getRandom().nextBytes(bytes);
}
/**
* Generate and return a new session identifier.
*/
public synchronized String generateSessionId() {
byte random[] = new byte[16];
// Render the result as a String of hexadecimal digits
StringBuffer result = new StringBuffer();
int resultLenBytes = 0;
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)
result.append((char) ('0' + b1));
else
result.append((char) ('A' + (b1 - 10)));
if (b2 < 10)
result.append((char) ('0' + b2));
else
result.append((char) ('A' + (b2 - 10)));
resultLenBytes++;
}
}
return (result.toString());
}
/**
* @Description:
* @param args
* @author mahh
* @since:2015-5-20 下午02:07:45
*/
public static void main(String[] args) {
ManagerBaseTest managerBaseTest = new ManagerBaseTest();
System.out.println(managerBaseTest.generateSessionId());
}
}