diff --git a/spring-cloud-stream-binders/spring-cloud-stream-binder-kafka/src/main/resources/META-INF/spring.factories b/spring-cloud-stream-binders/spring-cloud-stream-binder-kafka/src/main/resources/META-INF/spring.binders
similarity index 56%
rename from spring-cloud-stream-binders/spring-cloud-stream-binder-kafka/src/main/resources/META-INF/spring.factories
rename to spring-cloud-stream-binders/spring-cloud-stream-binder-kafka/src/main/resources/META-INF/spring.binders
index 7f00520be..375468587 100644
--- a/spring-cloud-stream-binders/spring-cloud-stream-binder-kafka/src/main/resources/META-INF/spring.factories
+++ b/spring-cloud-stream-binders/spring-cloud-stream-binder-kafka/src/main/resources/META-INF/spring.binders
@@ -1,2 +1,2 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration:\
+kafka:\
org.springframework.cloud.stream.binder.kafka.config.KafkaServiceAutoConfiguration
diff --git a/spring-cloud-stream-binders/spring-cloud-stream-binder-rabbit/src/main/resources/META-INF/spring.factories b/spring-cloud-stream-binders/spring-cloud-stream-binder-rabbit/src/main/resources/META-INF/spring.binders
similarity index 56%
rename from spring-cloud-stream-binders/spring-cloud-stream-binder-rabbit/src/main/resources/META-INF/spring.factories
rename to spring-cloud-stream-binders/spring-cloud-stream-binder-rabbit/src/main/resources/META-INF/spring.binders
index cde4a6309..7a65c4682 100644
--- a/spring-cloud-stream-binders/spring-cloud-stream-binder-rabbit/src/main/resources/META-INF/spring.factories
+++ b/spring-cloud-stream-binders/spring-cloud-stream-binder-rabbit/src/main/resources/META-INF/spring.binders
@@ -1,2 +1,2 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration:\
+rabbit:\
org.springframework.cloud.stream.binder.rabbit.config.RabbitServiceAutoConfiguration
diff --git a/spring-cloud-stream-binders/spring-cloud-stream-binder-redis/src/main/resources/META-INF/spring.factories b/spring-cloud-stream-binders/spring-cloud-stream-binder-redis/src/main/resources/META-INF/spring.binders
similarity index 56%
rename from spring-cloud-stream-binders/spring-cloud-stream-binder-redis/src/main/resources/META-INF/spring.factories
rename to spring-cloud-stream-binders/spring-cloud-stream-binder-redis/src/main/resources/META-INF/spring.binders
index acd5c3a0c..12ae7ef61 100644
--- a/spring-cloud-stream-binders/spring-cloud-stream-binder-redis/src/main/resources/META-INF/spring.factories
+++ b/spring-cloud-stream-binders/spring-cloud-stream-binder-redis/src/main/resources/META-INF/spring.binders
@@ -1,2 +1,2 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration:\
+redis:\
org.springframework.cloud.stream.binder.redis.config.RedisServiceAutoConfiguration
diff --git a/spring-cloud-stream-samples/multibinder-differentsystems/pom.xml b/spring-cloud-stream-samples/multibinder-differentsystems/pom.xml
new file mode 100644
index 000000000..35addd9c3
--- /dev/null
+++ b/spring-cloud-stream-samples/multibinder-differentsystems/pom.xml
@@ -0,0 +1,102 @@
+
+
+ 4.0.0
+
+ spring-cloud-stream-sample-multibinder-differentsystems
+ jar
+ spring-cloud-stream-sample-multibinder-differentsystems
+
+ Demo project for multiple binders of the same type (Kafka), connecting to different systems (broker groups)
+
+
+
+ org.springframework.cloud
+ spring-cloud-stream-samples
+ 1.0.0.BUILD-SNAPSHOT
+
+
+
+ multibinder.MultibinderApplication
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-stream
+
+
+ org.springframework.cloud
+ spring-cloud-stream-sample-source
+
+
+ org.springframework.cloud
+ spring-cloud-stream-sample-transform
+
+
+ org.springframework.cloud
+ spring-cloud-stream-sample-sink
+
+
+ org.springframework.cloud
+ spring-cloud-stream-binder-redis
+
+
+ org.springframework.cloud
+ spring-cloud-stream-binder-kafka
+
+
+ org.springframework.cloud
+ spring-cloud-stream-test-support-internal
+ test
+
+
+ org.apache.kafka
+ kafka_2.10
+ test
+ 0.8.2.1
+ test
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+
+
+ org.apache.curator
+ curator-test
+ 2.6.0
+ test
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ exec
+
+
+
+
+
+
diff --git a/spring-cloud-stream-samples/multibinder-differentsystems/src/main/java/multibinder/BridgeTransformer.java b/spring-cloud-stream-samples/multibinder-differentsystems/src/main/java/multibinder/BridgeTransformer.java
new file mode 100644
index 000000000..d68720ffe
--- /dev/null
+++ b/spring-cloud-stream-samples/multibinder-differentsystems/src/main/java/multibinder/BridgeTransformer.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package multibinder;
+
+import org.springframework.cloud.stream.annotation.EnableBinding;
+import org.springframework.cloud.stream.messaging.Processor;
+import org.springframework.integration.annotation.ServiceActivator;
+
+/**
+ * @author Marius Bogoevici
+ */
+@EnableBinding(Processor.class)
+public class BridgeTransformer {
+
+ @ServiceActivator(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
+ public Object transform(Object payload) {
+ return payload;
+ }
+}
diff --git a/spring-cloud-stream-samples/multibinder-differentsystems/src/main/java/multibinder/MultibinderApplication.java b/spring-cloud-stream-samples/multibinder-differentsystems/src/main/java/multibinder/MultibinderApplication.java
new file mode 100644
index 000000000..7aba5f67b
--- /dev/null
+++ b/spring-cloud-stream-samples/multibinder-differentsystems/src/main/java/multibinder/MultibinderApplication.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package multibinder;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class MultibinderApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(MultibinderApplication.class, args);
+ }
+
+}
diff --git a/spring-cloud-stream-samples/multibinder-differentsystems/src/main/resources/application.yml b/spring-cloud-stream-samples/multibinder-differentsystems/src/main/resources/application.yml
new file mode 100644
index 000000000..ca88423b9
--- /dev/null
+++ b/spring-cloud-stream-samples/multibinder-differentsystems/src/main/resources/application.yml
@@ -0,0 +1,33 @@
+server:
+ port: 8082
+spring:
+ cloud:
+ stream:
+ bindings:
+ input:
+ destination: dataIn
+ binder: kafka1
+ output:
+ destination: dataOut
+ binder: kafka2
+ binders:
+ kafka1:
+ type: kafka
+ environment:
+ spring:
+ cloud:
+ stream:
+ binder:
+ kafka:
+ brokers: ${kafkaBroker1}
+ zkNodes: ${zk1}
+ kafka2:
+ type: kafka
+ environment:
+ spring:
+ cloud:
+ stream:
+ binder:
+ kafka:
+ brokers: ${kafkaBroker2}
+ zkNodes: ${zk2}
diff --git a/spring-cloud-stream-samples/multibinder-differentsystems/src/test/java/multibinder/TwoKafkaBindersApplicationTest.java b/spring-cloud-stream-samples/multibinder-differentsystems/src/test/java/multibinder/TwoKafkaBindersApplicationTest.java
new file mode 100644
index 000000000..62dd8dc0b
--- /dev/null
+++ b/spring-cloud-stream-samples/multibinder-differentsystems/src/test/java/multibinder/TwoKafkaBindersApplicationTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package multibinder;
+
+import java.util.UUID;
+
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.SpringApplicationConfiguration;
+import org.springframework.cloud.stream.binder.BinderFactory;
+import org.springframework.cloud.stream.test.junit.kafka.KafkaTestSupport;
+import org.springframework.cloud.stream.test.junit.redis.RedisTestSupport;
+import org.springframework.integration.channel.DirectChannel;
+import org.springframework.integration.channel.QueueChannel;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageChannel;
+import org.springframework.messaging.support.MessageBuilder;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringApplicationConfiguration(classes = MultibinderApplication.class)
+@WebAppConfiguration
+@DirtiesContext
+public class TwoKafkaBindersApplicationTest {
+
+ @ClassRule
+ public static KafkaTestSupport kafkaTestSupport1 = new KafkaTestSupport();
+
+ @ClassRule
+ public static KafkaTestSupport kafkaTestSupport2 = new KafkaTestSupport();
+
+ @ClassRule
+ public static RedisTestSupport redisTestSupport = new RedisTestSupport();
+
+ @BeforeClass
+ public static void setupEnvironment() {
+ System.setProperty("kafkaBroker1", kafkaTestSupport1.getBrokerAddress());
+ System.setProperty("zk1", kafkaTestSupport1.getZkConnectString());
+ System.setProperty("kafkaBroker2", kafkaTestSupport2.getBrokerAddress());
+ System.setProperty("zk2", kafkaTestSupport2.getZkConnectString());
+ }
+
+ @Autowired
+ private BinderFactory binderFactory;
+
+ @Test
+ public void contextLoads() {
+ }
+
+ @Test
+ public void messagingWorks() {
+ DirectChannel dataProducer = new DirectChannel();
+ binderFactory.getBinder("kafka1").bindProducer("dataIn", dataProducer, null);
+
+ QueueChannel dataConsumer = new QueueChannel();
+ binderFactory.getBinder("kafka2").bindPubSubConsumer("dataOut", dataConsumer,
+ UUID.randomUUID().toString(), null);
+
+ String testPayload = "testFoo" + UUID.randomUUID().toString();
+ dataProducer.send(MessageBuilder.withPayload(testPayload).build());
+
+ Message> receive = dataConsumer.receive(2000);
+ Assert.assertThat(receive, Matchers.notNullValue());
+ Assert.assertThat(receive.getPayload(), CoreMatchers.equalTo(testPayload));
+ }
+
+}
diff --git a/spring-cloud-stream-samples/multibinder/pom.xml b/spring-cloud-stream-samples/multibinder/pom.xml
new file mode 100644
index 000000000..36ebe1d7f
--- /dev/null
+++ b/spring-cloud-stream-samples/multibinder/pom.xml
@@ -0,0 +1,79 @@
+
+
+ 4.0.0
+
+ spring-cloud-stream-sample-multibinder
+ jar
+ spring-cloud-stream-sample-multibinder
+ Demo project for multiple binders of different types (Redis and Rabbit)
+
+
+ org.springframework.cloud
+ spring-cloud-stream-samples
+ 1.0.0.BUILD-SNAPSHOT
+
+
+
+ multibinder.MultibinderApplication
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-stream
+
+
+ org.springframework.cloud
+ spring-cloud-stream-sample-source
+
+
+ org.springframework.cloud
+ spring-cloud-stream-sample-transform
+
+
+ org.springframework.cloud
+ spring-cloud-stream-sample-sink
+
+
+ org.springframework.cloud
+ spring-cloud-stream-binder-redis
+
+
+ org.springframework.cloud
+ spring-cloud-stream-binder-rabbit
+
+
+ org.springframework.cloud
+ spring-cloud-stream-test-support-internal
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-redis
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ exec
+
+
+
+
+
+
diff --git a/spring-cloud-stream-samples/multibinder/src/main/java/multibinder/BridgeTransformer.java b/spring-cloud-stream-samples/multibinder/src/main/java/multibinder/BridgeTransformer.java
new file mode 100644
index 000000000..d68720ffe
--- /dev/null
+++ b/spring-cloud-stream-samples/multibinder/src/main/java/multibinder/BridgeTransformer.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package multibinder;
+
+import org.springframework.cloud.stream.annotation.EnableBinding;
+import org.springframework.cloud.stream.messaging.Processor;
+import org.springframework.integration.annotation.ServiceActivator;
+
+/**
+ * @author Marius Bogoevici
+ */
+@EnableBinding(Processor.class)
+public class BridgeTransformer {
+
+ @ServiceActivator(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
+ public Object transform(Object payload) {
+ return payload;
+ }
+}
diff --git a/spring-cloud-stream-samples/multibinder/src/main/java/multibinder/MultibinderApplication.java b/spring-cloud-stream-samples/multibinder/src/main/java/multibinder/MultibinderApplication.java
new file mode 100644
index 000000000..7aba5f67b
--- /dev/null
+++ b/spring-cloud-stream-samples/multibinder/src/main/java/multibinder/MultibinderApplication.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package multibinder;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class MultibinderApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(MultibinderApplication.class, args);
+ }
+
+}
diff --git a/spring-cloud-stream-samples/multibinder/src/main/resources/application.yml b/spring-cloud-stream-samples/multibinder/src/main/resources/application.yml
new file mode 100644
index 000000000..9c3cb2180
--- /dev/null
+++ b/spring-cloud-stream-samples/multibinder/src/main/resources/application.yml
@@ -0,0 +1,12 @@
+server:
+ port: 8082
+spring:
+ cloud:
+ stream:
+ bindings:
+ input:
+ destination: dataIn
+ binder: redis
+ output:
+ destination: dataOut
+ binder: rabbit
diff --git a/spring-cloud-stream-samples/multibinder/src/test/java/multibinder/RabbitAndRedisBinderApplicationTests.java b/spring-cloud-stream-samples/multibinder/src/test/java/multibinder/RabbitAndRedisBinderApplicationTests.java
new file mode 100644
index 000000000..7ebfbe922
--- /dev/null
+++ b/spring-cloud-stream-samples/multibinder/src/test/java/multibinder/RabbitAndRedisBinderApplicationTests.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package multibinder;
+
+import java.util.UUID;
+
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.SpringApplicationConfiguration;
+import org.springframework.cloud.stream.binder.BinderFactory;
+import org.springframework.cloud.stream.test.junit.rabbit.RabbitTestSupport;
+import org.springframework.cloud.stream.test.junit.redis.RedisTestSupport;
+import org.springframework.integration.channel.DirectChannel;
+import org.springframework.integration.channel.QueueChannel;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageChannel;
+import org.springframework.messaging.support.MessageBuilder;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringApplicationConfiguration(classes = MultibinderApplication.class)
+@WebAppConfiguration
+@DirtiesContext
+public class RabbitAndRedisBinderApplicationTests {
+
+ @ClassRule
+ public static RabbitTestSupport rabbitTestSupport = new RabbitTestSupport();
+
+ @ClassRule
+ public static RedisTestSupport redisTestSupport = new RedisTestSupport();
+
+ @Autowired
+ private BinderFactory binderFactory;
+
+ @Test
+ public void contextLoads() {
+ }
+
+ @Test
+ public void messagingWorks() {
+ DirectChannel dataProducer = new DirectChannel();
+ binderFactory.getBinder("redis").bindProducer("dataIn", dataProducer,null);
+
+ QueueChannel dataConsumer = new QueueChannel();
+ binderFactory.getBinder("rabbit").bindPubSubConsumer("dataOut", dataConsumer,
+ UUID.randomUUID().toString(),null);
+
+ String testPayload = "testFoo" + UUID.randomUUID().toString();
+ dataProducer.send(MessageBuilder.withPayload(testPayload).build());
+
+ Message> receive = dataConsumer.receive(2000);
+ Assert.assertThat(receive, Matchers.notNullValue());
+ Assert.assertThat(receive.getPayload(), CoreMatchers.equalTo(testPayload));
+ }
+
+}
diff --git a/spring-cloud-stream-samples/pom.xml b/spring-cloud-stream-samples/pom.xml
index d506c9197..53c0f3b66 100644
--- a/spring-cloud-stream-samples/pom.xml
+++ b/spring-cloud-stream-samples/pom.xml
@@ -25,6 +25,8 @@
tapdoubleextended
+ multibinder
+ multibinder-differentsystemsrxjava-processor
diff --git a/spring-cloud-stream-test-support-internal/src/main/java/org/springframework/cloud/stream/test/junit/kafka/KafkaTestSupport.java b/spring-cloud-stream-test-support-internal/src/main/java/org/springframework/cloud/stream/test/junit/kafka/KafkaTestSupport.java
index a922dc2a3..b6ef10a14 100644
--- a/spring-cloud-stream-test-support-internal/src/main/java/org/springframework/cloud/stream/test/junit/kafka/KafkaTestSupport.java
+++ b/spring-cloud-stream-test-support-internal/src/main/java/org/springframework/cloud/stream/test/junit/kafka/KafkaTestSupport.java
@@ -19,6 +19,13 @@ package org.springframework.cloud.stream.test.junit.kafka;
import java.util.Properties;
+import kafka.server.KafkaConfig;
+import kafka.server.KafkaServer;
+import kafka.utils.SystemTime$;
+import kafka.utils.TestUtils;
+import kafka.utils.Utils;
+import kafka.utils.ZKStringSerializer$;
+import kafka.utils.ZkUtils;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkInterruptedException;
import org.junit.Rule;
@@ -26,15 +33,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.stream.test.junit.AbstractExternalResourceTestSupport;
-
-import kafka.server.KafkaConfig;
-import kafka.server.KafkaServer;
-import kafka.utils.SystemTime$;
-import kafka.utils.TestUtils;
-import kafka.utils.TestZKUtils;
-import kafka.utils.Utils;
-import kafka.utils.ZKStringSerializer$;
-import kafka.utils.ZkUtils;
+import org.springframework.util.SocketUtils;
/**
@@ -105,7 +104,7 @@ public class KafkaTestSupport extends AbstractExternalResourceTestSupport binderFactory;
@Test
@SuppressWarnings("unchecked")
public void testWiring() {
Message message = new GenericMessage<>("hello");
processor.input().send(message);
- Message received = (Message) messageCollector.forChannel(processor.output()).poll();
+ Message received = (Message) ((TestSupportBinder) binderFactory.getBinder(null)).messageCollector().forChannel(processor.output()).poll();
assertThat(received.getPayload(), equalTo("hello world"));
}
diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/annotation/EnableBinding.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/annotation/EnableBinding.java
index 2f94e08a0..18e02eda2 100644
--- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/annotation/EnableBinding.java
+++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/annotation/EnableBinding.java
@@ -24,6 +24,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.cloud.stream.config.AggregateBuilderConfiguration;
+import org.springframework.cloud.stream.config.BinderFactoryConfiguration;
import org.springframework.cloud.stream.config.BindingBeansRegistrar;
import org.springframework.cloud.stream.config.ChannelBindingServiceConfiguration;
import org.springframework.context.annotation.Configuration;
@@ -33,7 +34,6 @@ import org.springframework.integration.config.EnableIntegration;
/**
* Enables the binding of inputs and outputs to a broker, according to the list
* of interfaces passed as value to the annotation.
- *
* @author Dave Syer
* @author Marius Bogoevici
* @author David Turanski
@@ -43,7 +43,8 @@ import org.springframework.integration.config.EnableIntegration;
@Documented
@Inherited
@Configuration
-@Import({ChannelBindingServiceConfiguration.class, AggregateBuilderConfiguration.class, BindingBeansRegistrar.class})
+@Import({ChannelBindingServiceConfiguration.class, AggregateBuilderConfiguration.class, BindingBeansRegistrar.class,
+ BinderFactoryConfiguration.class})
@EnableIntegration
public @interface EnableBinding {
diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderConfiguration.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderConfiguration.java
new file mode 100644
index 000000000..5cea72874
--- /dev/null
+++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderConfiguration.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.stream.binder;
+
+import java.util.Properties;
+
+/**
+ *
+ * Configuration for a binder instance, associating a {@link BinderType} with its configuration {@link Properties}.
+ * An application may contain multiple {@link BinderConfiguration}s per {@link BinderType}, when connecting to multiple
+ * systems of the same type.
+ *
+ * @author Marius Bogoevici
+ */
+public class BinderConfiguration {
+
+ private final BinderType binderType;
+
+ private final Properties properties;
+
+ /**
+ * @param binderType the binder type used by this configuration
+ * @param properties the properties for setting up the binder
+ */
+ public BinderConfiguration(BinderType binderType, Properties properties) {
+ this.binderType = binderType;
+ this.properties = properties;
+ }
+
+ public BinderType getBinderType() {
+ return binderType;
+ }
+
+ public Properties getProperties() {
+ return properties;
+ }
+}
diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderFactory.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderFactory.java
new file mode 100644
index 000000000..b0bf33804
--- /dev/null
+++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderFactory.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.stream.binder;
+
+/**
+ * @author Marius Bogoevici
+ */
+public interface BinderFactory {
+
+ /**
+ * Returns the binder instance associated with the given configuration name. Instance caching is a requirement,
+ * and implementations must return the same instance on subsequent invocations with the same argument.
+ *
+ * @param configurationName the name of a binder configuration
+ * @return the binder instance
+ */
+ Binder getBinder(String configurationName);
+}
diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderType.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderType.java
new file mode 100644
index 000000000..2a910239b
--- /dev/null
+++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderType.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.stream.binder;
+
+import java.util.Arrays;
+
+/**
+ * References one or more {@link org.springframework.context.annotation.Configuration}-annotated classes which
+ * provide a context definition which contains exactly one {@link Binder}, typically for a given type of system (e.g.
+ * Rabbit, Kafka, Redis, etc.). An application may contain multiple instances of a given {@link BinderType},
+ * when connecting to multiple systems of the same type.
+ *
+ * @author Marius Bogoevici
+ */
+public class BinderType {
+
+ private final String defaultName;
+
+ private final Class>[] configurationClasses;
+
+ public BinderType(String defaultName, Class>[] configurationClasses) {
+ this.defaultName = defaultName;
+ this.configurationClasses = configurationClasses;
+ }
+
+ public String getDefaultName() {
+ return defaultName;
+ }
+
+ public Class>[] getConfigurationClasses() {
+ return configurationClasses;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ BinderType that = (BinderType) o;
+ if (!defaultName.equals(that.defaultName)) {
+ return false;
+ }
+ return Arrays.equals(configurationClasses, that.configurationClasses);
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = defaultName.hashCode();
+ result = 31 * result + Arrays.hashCode(configurationClasses);
+ return result;
+ }
+}
diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderTypeRegistry.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderTypeRegistry.java
new file mode 100644
index 000000000..ad0846531
--- /dev/null
+++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderTypeRegistry.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.stream.binder;
+
+import java.util.Map;
+
+/**
+ * A registry of {@link BinderType}s, indexed by name. A {@link BinderTypeRegistry} bean is created automatically
+ * based on information found in the {@literal META-INF/spring.binders} files provided by binder implementors.
+ * This can be overridden by registering a {@link BinderTypeRegistry} bean in the context.
+ *
+ * @author Marius Bogoevici
+ */
+public interface BinderTypeRegistry {
+
+ BinderType get(String name);
+
+ Map getAll();
+
+}
diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/DefaultBinderFactory.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/DefaultBinderFactory.java
new file mode 100644
index 000000000..daba7a1c8
--- /dev/null
+++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/DefaultBinderFactory.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.stream.binder;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.boot.Banner.Mode;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.EnvironmentAware;
+import org.springframework.core.env.Environment;
+import org.springframework.util.StringUtils;
+
+/**
+ * Default {@link BinderFactory} implementation.
+ *
+ * @author Marius Bogoevici
+ */
+public class DefaultBinderFactory implements BinderFactory, DisposableBean, EnvironmentAware {
+
+ private final Map binderConfigurations;
+
+ private final Map> binderInstanceCache = new HashMap<>();
+
+ private volatile Environment environment;
+
+ private volatile String defaultBinder;
+
+ public DefaultBinderFactory(Map binderConfigurations) {
+ this.binderConfigurations = new HashMap<>(binderConfigurations);
+ }
+
+ @Override
+ public void setEnvironment(Environment environment) {
+ this.environment = environment;
+ }
+
+ public void setDefaultBinder(String defaultBinder) {
+ this.defaultBinder = defaultBinder;
+ }
+
+ @Override
+ public void destroy() throws Exception {
+ for (Map.Entry> entry : binderInstanceCache.entrySet()) {
+ BinderInstanceHolder binderInstanceHolder = entry.getValue();
+ binderInstanceHolder.getBinderContext().close();
+ }
+ }
+
+ @Override
+ public synchronized Binder getBinder(String name) {
+ String configurationName;
+ // Fall back to a default if no argument is provided
+ if (StringUtils.isEmpty(name)) {
+ if (binderConfigurations.size() == 0) {
+ throw new IllegalStateException("A default binder has been requested, but there there is no binder available");
+ }
+ else if (binderConfigurations.size() == 1) {
+ configurationName = binderConfigurations.keySet().iterator().next();
+ }
+ else {
+ if (StringUtils.hasText(defaultBinder)) {
+ configurationName = defaultBinder;
+ }
+ else {
+ throw new IllegalStateException(
+ "A default binder has been requested, but there is more than one binder available: "
+ + StringUtils.collectionToCommaDelimitedString(binderConfigurations.keySet()) + ", and"
+ + " no default binder has been set.");
+ }
+ }
+ } else {
+ configurationName = name;
+ }
+ if (!binderInstanceCache.containsKey(configurationName)) {
+ BinderConfiguration binderConfiguration = binderConfigurations.get(configurationName);
+ if (binderConfiguration == null) {
+ throw new IllegalStateException("Unknown binder configuration: " + configurationName);
+ }
+ Properties binderProperties = binderConfiguration.getProperties();
+ // Convert all properties to arguments, so that they receive maximum precedence
+ ArrayList args = new ArrayList<>();
+ for (Map.Entry