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 . + +