* 採用MogoDB生成ID的策略
* 最終生成ID是24位16進制的字符串
* 構成:8位時間+6位機器碼+4位進程號+6位隨機數
* @author Rain
*
*/
public class IDGen {
private static Logger logger = Logger.getLogger(IDGen.class);
private static AtomicInteger nextInc = new AtomicInteger( (new java.util.Random()).nextInt() );
private static final int genMachine;
public static void main(String[] args) throws Exception{
System.out.println(IDGen.nextId()+"===>"+nextInc.getAndIncrement());
Thread.sleep(2000);
System.out.println(IDGen.nextId()+"==>"+nextInc.getAndIncrement());
}
static{
try {
// build a 2-byte machine piece based on NICs info
int machinePiece;
{
try {
StringBuilder sb = new StringBuilder();
Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
while ( e.hasMoreElements() ){
NetworkInterface ni = e.nextElement();
sb.append( ni.toString() );
}
machinePiece = sb.toString().hashCode() << 16;
} catch (Throwable e) {
// exception sometimes happens with IBM JVM, use random
// logger.log(Level.WARNING, e.getMessage(), e);
machinePiece = (new Random().nextInt()) << 16;
}
//logger.fine( "machine piece post: " + Integer.toHexString( machinePiece ) );
}
// add a 2 byte process piece. It must represent not only the JVM but the class loader.
// Since static var belong to class loader there could be collisions otherwise
final int processPiece;
{
int processId = new java.util.Random().nextInt();
try {
processId = java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode();
}
catch ( Throwable t ){
}
ClassLoader loader = IDGen.class.getClassLoader();
int loaderId = loader != null ? System.identityHashCode(loader) : 0;
StringBuilder sb = new StringBuilder();
sb.append(Integer.toHexString(processId));
sb.append(Integer.toHexString(loaderId));
processPiece = sb.toString().hashCode() & 0xFFFF;
logger.info( "process piece: " + Integer.toHexString( processPiece ) );
}
genMachine = machinePiece | processPiece;
logger.info( "machine : " + Integer.toHexString( genMachine ) );
}
catch ( Exception e ){
throw new RuntimeException( e );
}
}
public static String nextId(){
byte toByteArray[] = new byte[12];
ByteBuffer bb = ByteBuffer.wrap( toByteArray );
//by default BB is big endian like we need
bb.putInt((int)(System.currentTimeMillis()/1000) );
bb.putInt(genMachine);
bb.putInt(nextInc.getAndIncrement());
final StringBuilder buf = new StringBuilder(24);
for(final byte b : toByteArray) {
buf.append(String.format("%02x", b & 0xff));
}
return buf.toString();
}
}