前言 因为http是无状态的,所以产生了cookie,session机制来构造一个会话。
一般流程是这样:
客户端发送请求
服务端接收请求,并且设置Set-Cookie头,分配一个sessionId
客户端存在cookie,下次发送时带上sessionid
服务端解析sessionid,找到对应的session信息
所以我们可以知道,核心就在这个sessionid身上。
那么这个sessionid需要哪些特质呢
Tomcat的实现 由于本人算法渣,自己想不到什么好办法实现,所以就去看了Tomcat怎么实现。
SecureRandom 1 2 3 4 5 6 public class SecureRandom extends java .util .Random {}
SessionIdGenerator 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public interface SessionIdGenerator { public String getJvmRoute () ; public void setJvmRoute (String jvmRoute) ; public int getSessionIdLength () ; public void setSessionIdLength (int sessionIdLength) ; public String generateSessionId () ; public String generateSessionId (String route) ; }
SessionIdGeneratorBase 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 public abstract class SessionIdGeneratorBase extends LifecycleBase implements SessionIdGenerator { private final Queue<SecureRandom> randoms = new ConcurrentLinkedQueue<>(); private String secureRandomClass = null ; private String secureRandomAlgorithm = "SHA1PRNG" ; private String secureRandomProvider = null ; private String jvmRoute = "" ; private int sessionIdLength = 16 ; public String generateSessionId () { return generateSessionId(jvmRoute); } protected void getRandomBytes (byte bytes[]) { SecureRandom random = randoms.poll(); if (random == null ) { random = createSecureRandom(); } random.nextBytes(bytes); randoms.add(random); } private SecureRandom createSecureRandom () { SecureRandom result = null ; long t1 = System.currentTimeMillis(); if (secureRandomClass != null ) { try { Class<?> clazz = Class.forName(secureRandomClass); result = (SecureRandom) clazz.getConstructor().newInstance(); } catch (Exception e) { log.error(sm.getString("sessionIdGeneratorBase.random" , secureRandomClass), e); } } boolean error = false ; if (result == null ) { ... } if (result == null && error) { .... } if (result == null ) { result = new SecureRandom(); } result.nextInt(); long t2 = System.currentTimeMillis(); if ((t2 - t1) > 100 ) { log.warn(sm.getString("sessionIdGeneratorBase.createRandom" , result.getAlgorithm(), Long.valueOf(t2 - t1))); } return result; } }
StandardSessionIdGenerator 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public class StandardSessionIdGenerator extends SessionIdGeneratorBase { public String generateSessionId (String route) { byte random[] = new byte [16 ]; int sessionIdLength = getSessionIdLength(); StringBuilder buffer = new StringBuilder(2 * sessionIdLength + 20 ); int resultLenBytes = 0 ; while (resultLenBytes < sessionIdLength) { getRandomBytes(random); for (int j = 0 ; j < random.length && resultLenBytes < 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 (route != null && route.length() > 0 ) { buffer.append('.' ).append(route); } else { String jvmRoute = getJvmRoute(); if (jvmRoute != null && jvmRoute.length() > 0 ) { buffer.append('.' ).append(jvmRoute); } } return buffer.toString(); } }
总结 总的来说
Tomcat的sessionid的生成主要是随机数,依赖的类是java.security.SecureRandom
为了避免多线程竞争的问题,引入了一个queue,当SecureRandom不够用就生成一个。
同时在集群中加入了本机的编号