diff --git a/build.gradle b/build.gradle
index aceb205ee6..52d4d80150 100644
--- a/build.gradle
+++ b/build.gradle
@@ -27,6 +27,7 @@ allprojects {
repositories {
maven { url 'http://repo.springsource.org/libs-milestone' }
maven { url 'http://repo.springsource.org/plugins-release' }
+ mavenCentral()
}
}
@@ -55,6 +56,7 @@ subprojects { subproject ->
junitVersion = '4.11'
log4jVersion = '1.2.12'
mockitoVersion = '1.9.5'
+ eaioUUIDVersion = '3.2'
springVersionDefault = '3.1.4.RELEASE'
springVersion = project.hasProperty('springVersion') ? getProperty('springVersion') : springVersionDefault
@@ -180,6 +182,7 @@ project('spring-integration-core') {
compile "org.springframework:spring-context:$springVersion"
compile "org.springframework:spring-tx:$springVersion"
compile "org.springframework.retry:spring-retry:$springRetryVersion"
+ compile "com.eaio.uuid:uuid:$eaioUUIDVersion"
compile("org.codehaus.jackson:jackson-mapper-asl:$jacksonVersion", optional)
compile("com.fasterxml.jackson.core:jackson-databind:$jackson2Version", optional)
testCompile "org.aspectj:aspectjweaver:$aspectjVersion"
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/MessageHeaders.java b/spring-integration-core/src/main/java/org/springframework/integration/MessageHeaders.java
index 4be5a9617a..c71a1ee1c9 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/MessageHeaders.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/MessageHeaders.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,10 +28,13 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import com.eaio.uuid.UUIDGen;
+
/**
* The headers for a {@link Message}.
* IMPORTANT: MessageHeaders are immutable. Any mutating operation (e.g., put(..), putAll(..) etc.)
@@ -97,8 +100,9 @@ public final class MessageHeaders implements Map, Serializable {
public MessageHeaders(Map headers) {
this.headers = (headers != null) ? new HashMap(headers) : new HashMap();
- if (MessageHeaders.idGenerator == null){
- this.headers.put(ID, UUID.randomUUID());
+ if (MessageHeaders.idGenerator == null) {
+ UUID uuid = new UUID(UUIDGen.newTime(), UUIDGen.getClockSeqAndNode());
+ this.headers.put(ID, uuid);
}
else {
this.headers.put(ID, MessageHeaders.idGenerator.generateId());
@@ -271,4 +275,31 @@ public final class MessageHeaders implements Map, Serializable {
public static interface IdGenerator {
UUID generateId();
}
+
+ public static class JdkIdGenerator implements IdGenerator {
+
+ @Override
+ public UUID generateId() {
+ return UUID.randomUUID();
+ }
+
+ }
+
+ public static class SimpleIncrementingIdGenerator implements IdGenerator {
+
+ private final AtomicLong topBits = new AtomicLong();
+
+ private final AtomicLong bottomBits = new AtomicLong();
+
+ @Override
+ public UUID generateId() {
+ long bottomBits = this.bottomBits.incrementAndGet();
+ if (bottomBits == 0) {
+ this.topBits.incrementAndGet();
+ }
+ return new UUID(this.topBits.get(), bottomBits);
+ }
+
+ }
+
}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/IdGeneratorConfigurer.java b/spring-integration-core/src/main/java/org/springframework/integration/config/IdGeneratorConfigurer.java
index 7da60342c7..ba61f5626f 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/IdGeneratorConfigurer.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/IdGeneratorConfigurer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,8 @@
package org.springframework.integration.config;
import java.lang.reflect.Field;
+import java.util.HashSet;
+import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -35,30 +37,35 @@ import org.springframework.util.ReflectionUtils;
/**
* @author Oleg Zhurakousky
* @author Mark Fisher
+ * @author Gary Russell
* @since 2.0.4
*/
public final class IdGeneratorConfigurer implements ApplicationListener {
- private static volatile String generatorContextId;
+ private static final Set generatorContextId = new HashSet();
+
+ private static volatile IdGenerator theIdGenerator;
private final Log logger = LogFactory.getLog(getClass());
- public void onApplicationEvent(ApplicationContextEvent event) {
+ public synchronized void onApplicationEvent(ApplicationContextEvent event) {
ApplicationContext context = event.getApplicationContext();
if (event instanceof ContextRefreshedEvent) {
boolean contextHasIdGenerator = context.getBeanNamesForType(IdGenerator.class).length > 0;
if (contextHasIdGenerator) {
if (this.setIdGenerator(context)) {
- IdGeneratorConfigurer.generatorContextId = context.getId();
+ IdGeneratorConfigurer.generatorContextId.add(context.getId());
}
}
}
else if (event instanceof ContextClosedEvent) {
- if (context.getId().equals(IdGeneratorConfigurer.generatorContextId)) {
- this.unsetIdGenerator();
- IdGeneratorConfigurer.generatorContextId = null;
+ if (IdGeneratorConfigurer.generatorContextId.contains(context.getId())) {
+ if (IdGeneratorConfigurer.generatorContextId.size() == 1) {
+ this.unsetIdGenerator();
+ }
+ IdGeneratorConfigurer.generatorContextId.remove(context.getId());
}
- }
+ }
}
private boolean setIdGenerator(ApplicationContext context) {
@@ -76,19 +83,34 @@ public final class IdGeneratorConfigurer implements ApplicationListener 1 && logger.isWarnEnabled()) {
+ logger.warn("Found too many 'IdGenerator' beans (" + idBeans + ") " +
+ "Will use the existing UUID strategy.");
+ }
+ else if (logger.isDebugEnabled()) {
+ logger.debug("Unable to locate MessageHeaders.IdGenerator. Will use the existing UUID strategy.");
}
return false;
}
@@ -96,7 +118,7 @@ public final class IdGeneratorConfigurer implements ApplicationListener
+
+ Message ID Generation
+
+ When a message transitions through an application, each time it is
+ mutated (e.g. by a transformer) a new message id is assigned. The message id is
+ a UUID. Beginning with Spring Integration 3.0, the default strategy
+ used for id generation is to use the com.eaio.uuid package to
+ generate Type 1 UUIDs. This is much more efficient than the previous
+ java.util.UUID.randomUUID() implementation.
+
+
+ A different UUID generation strategy can be selected by declaring a bean that implements
+ MessageHeaders.IdGenerator in the application context.
+
+
+ Only one UUID generation strategy can be used in a classloader. This means that if
+ two or more application contexts are running in the same classloader, they will share
+ the same strategy. If one of the contexts changes the strategy, it will be used by
+ all contexts. If two or more contexts in the same classloader declare a bean of type
+ MessageHeaders.IdGenerator, they must all be an instance
+ of the same class, otherwise the context attempting to replace a custom strategy will
+ fail to initialize. If the strategy is the same, but parameterized, the strategy in the
+ first context to initialize will be used.
+
+
+ In addition to the default strategy, two additional IdGenerators
+ are provided; MessageHeaders.JdkIdGenerator uses the previous
+ UUID.randomUUID() mechanism; MessageHeaders.SimpleIncrementingIdGenerator
+ can be used in cases where a UUID is not really needed and a simple incrementing
+ value is sufficient.
+
+
+ The default strategy of creating Type 1 UUIDs may present security concerns for some users
+ because the UUID contains the MAC address of a network interface on the platform. For these
+ users, an alternate strategy should be selected.
+
+
diff --git a/src/reference/docbook/whats-new.xml b/src/reference/docbook/whats-new.xml
index 97cf478216..1d2cface15 100644
--- a/src/reference/docbook/whats-new.xml
+++ b/src/reference/docbook/whats-new.xml
@@ -234,5 +234,15 @@
ImapIdleExceptionEvent or one of its super classes.
+
+ Message ID Generation
+
+ Previously, message ids were generated using the JDK UUID.randomUUID() method. With this
+ release, the default mechanism has been changed to use the com.eaio.uuid package which
+ generates Type 1 UUIDs, and is significantly faster. In addition, the ability to change
+ the strategy used to generate message ids has been added.
+ For more information see .
+
+