编程示例: Session Id的生成

实现思路

Session的实现方式如下:在用户第一次登录的时候,系统为它分配一个唯一Id(被称为Session Id)作为标识,并且
记录下这个用户的用户名、要登录的账套名、用户拥有的权限等,以Id为键,用户名、账套名等信息为值保存到一
张Session哈希表中。以后客户端登录的时候只要提供此Id即可,应用服务器可以通过此Id到Session哈希表中查询
到所需要的一切信息。因为Session哈希表是保存在存储器中的(通常是内存),存储过多的Session信息将会占用内存
空间,所以客户端退出的时候要通知应用服务器注销此Id。

具体到细节还有一些问题需要处理:

l   如何生成唯一的Id。

l   如何保存用户名、账套名等信息,如何能在Session中放入自定义的信息。

l   如何维护管理Session。

l   如何清除Session。当系统非正常退出的时候,比如客户端机器故障,客户端是无法通知应用服务器注销Id的,
这会造成应用服务器中存在垃圾Session。

l   如何防止此Id被恶意程序截获,从而冒充合法客户端登录系统。

 Session Id的生成

客户端Session Id的生成与数据库中的主键生成面对的问题是类似的。以可移植、高效率、可靠的方式来生成主键是一个非常重要的问题。可移植指的是主键生成策略不能依赖于服务器、操作系统、数据库等;高效率是生成主键的过程必须足够快,不能让生成主键的算法成为系统的瓶颈;可靠指的是生成的主键必须保证唯一性。主键生成方式可以分为数据库相关方式和数据库无关方式两种。

数据库相关方式是通过数据库的帮助来生成主键。对于支持自增字段的数据库,可以借助其序列号发生器来产生唯一的主键;对于不支持自增字段的数据库,可以在系统中放置一张表,采用此表记录本次生成的主键,这样就保证了生成的主键与以前的不冲突。数据库相关方式的优点是实现简单,而且可以完全保证生成主键的唯一性;不过由于需要数据库来维护主键的状态和同步对主键生成器的访问,所以对数据库有依赖性,而且由于需要访问数据库,其生成速度较慢。

数据无关方式是无须依靠数据库而生成主键的方式。最典型的算法就是UUID算法。UUID是一个字符串,它被编码为包含了使生成的UUID在整个空间和时间上都完全唯一的所必需的系统信息集,不管这个UUID是何时何地被生成的。原始的UUID规范是由Paul Leach和Rich Salz在网络工作组因特网草案中定义的。

UUID字符串一般由下面信息构成:

l   系统时钟的毫秒值。这是通过System.currentTimeMillis()方法得到的。这保证了在时间维度上产生主键的唯一性。

l   网络IP或者网卡标识。这保证了在集群环境中产生主键的唯一性。

l   精确到在一个JVM内部的对象的唯一。通常是System.identityHashCode(this)所调用产生的编码,这个方法调用保证对JVM中不同对象返回不同的整数。即使在同一台机器上存在多个JVM,两个UUID生成器返回相同的UUID的情况也极不可能发生。

l   在一个对象内的毫秒级的唯一。这是由与每一个方法调用所对应的随机整数,这个随机整数是通过使用java.security.SecureRandom类生成的。这可以保证在同一毫秒内对同一个方法的多个调用都是唯一的。

上述这些部分组合在一起,就可以保证生成的UUID在所有机器中(IP不重复或者网卡地址不重复),以及在同一台机器上的JVM内部的所有UUID生成器的实例中都保持唯一,并且能精确到毫秒级甚至是一个毫秒内的单个方法调用的级别。

流行的UUID算法有很多,这些算法有的不能完全保证生成的UUID的唯一性,必须根据情况选用。下面推荐两种UUID实现算法。

【例】UUID.Hex算法。

这个算法是Hibernate中主键策略为“uuid.hex”时所使用的算法,代码位于包org.hibernate.id下的UUIDHexGenerator.java文件中。

调用方法:

IdentifierGenerator gen = new UUIDHexGenerator();

for (int i = 0; i < 10; i++)

{

    String id = (String) gen.generate(null, null);

    System.out.println(id);

}

运行结果(UUID的生成是不重复的,每次的运行结果都会不同):

你可能感兴趣的:(编程示例,java,UUID算法)