Use alternative UUID strategy in MessageHeaders

This change adds an alternative UUID generation strategy to use by
default in MessageHeaders. Instead of using SecureRandom for each
new UUID, SecureRandom is used only for the initial seed to be
provided java.util.Random. Thereafter the same Random instance is
used instead. This provides improved performance while id's are
still random but less securely so.
This commit is contained in:
Rossen Stoyanchev
2013-10-14 21:55:13 -04:00
parent 57d127b55a
commit 70dfec269b
2 changed files with 195 additions and 8 deletions

View File

@@ -20,6 +20,8 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -28,6 +30,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
@@ -56,6 +59,7 @@ import org.apache.commons.logging.LogFactory;
* @author Arjen Poutsma
* @author Mark Fisher
* @author Gary Russell
* @author Rossen Stoyanchev
* @since 4.0
* @see org.springframework.messaging.support.MessageBuilder
*/
@@ -65,9 +69,10 @@ public final class MessageHeaders implements Map<String, Object>, Serializable {
private static final Log logger = LogFactory.getLog(MessageHeaders.class);
private static volatile IdGenerator idGenerator = null;
private static volatile IdGenerator defaultIdGenerator = new AlternativeJdkIdGenerator();
/**
* The key for the Message ID. This is an automatically generated UUID and
* should never be explicitly set in the header map <b>except</b> in the
@@ -92,13 +97,8 @@ public final class MessageHeaders implements Map<String, Object>, Serializable {
public MessageHeaders(Map<String, Object> headers) {
this.headers = (headers != null) ? new HashMap<String, Object>(headers) : new HashMap<String, Object>();
if (MessageHeaders.idGenerator == null){
this.headers.put(ID, UUID.randomUUID());
}
else {
this.headers.put(ID, MessageHeaders.idGenerator.generateId());
}
IdGenerator generatorToUse = (idGenerator != null) ? idGenerator : defaultIdGenerator;
this.headers.put(ID, generatorToUse.generateId());
this.headers.put(TIMESTAMP, new Long(System.currentTimeMillis()));
}
@@ -247,4 +247,37 @@ public final class MessageHeaders implements Map<String, Object>, Serializable {
public static interface IdGenerator {
UUID generateId();
}
/**
* A variation of {@link UUID#randomUUID()} that uses {@link SecureRandom} only for
* the initial seed and {@link Random} thereafter, which provides better performance
* in exchange for less securely random id's.
*/
public static class AlternativeJdkIdGenerator implements IdGenerator {
private final Random random;
public AlternativeJdkIdGenerator() {
byte[] seed = new SecureRandom().generateSeed(8);
this.random = new Random(new BigInteger(seed).longValue());
}
public UUID generateId() {
byte[] randomBytes = new byte[16];
this.random.nextBytes(randomBytes);
long mostSigBits = 0;
for (int i = 0; i < 8; i++) {
mostSigBits = (mostSigBits << 8) | (randomBytes[i] & 0xff);
}
long leastSigBits = 0;
for (int i = 8; i < 16; i++) {
leastSigBits = (leastSigBits << 8) | (randomBytes[i] & 0xff);
}
return new UUID(mostSigBits, leastSigBits);
}
}
}