diff --git a/spring-boot-examples/consumer-app/pom.xml b/spring-boot-examples/consumer-app/pom.xml
new file mode 100644
index 000000000..63df3df40
--- /dev/null
+++ b/spring-boot-examples/consumer-app/pom.xml
@@ -0,0 +1,99 @@
+
+
+ 4.0.0
+
+ io.dapr
+ spring-boot-examples
+ 0.14.0-SNAPSHOT
+
+
+ consumer-app
+ consumer-app
+ Spring Boot, Testcontainers and Dapr Integration Examples :: Consumer App
+
+
+ 3.2.6
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${springboot.version}
+ pom
+ import
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ io.dapr.spring
+ dapr-spring-boot-starter
+ ${dapr-java-sdk.alpha-version}
+
+
+
+ io.dapr.spring
+ dapr-spring-boot-starter
+ ${dapr.sdk.alpha.version}
+
+
+
+ io.dapr.spring
+ dapr-spring-boot-starter-test
+ ${dapr.sdk.alpha.version}
+ test
+
+
+
+ org.testcontainers
+ junit-jupiter
+ test
+
+
+ org.testcontainers
+ postgresql
+ 1.20.0
+ test
+
+
+ org.testcontainers
+ rabbitmq
+ 1.20.0
+ test
+
+
+ org.testcontainers
+ kafka
+ 1.20.0
+ test
+
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/spring-boot-examples/consumer-app/src/main/java/io/dapr/springboot/examples/consumer/ConsumerApplication.java b/spring-boot-examples/consumer-app/src/main/java/io/dapr/springboot/examples/consumer/ConsumerApplication.java
new file mode 100644
index 000000000..615340861
--- /dev/null
+++ b/spring-boot-examples/consumer-app/src/main/java/io/dapr/springboot/examples/consumer/ConsumerApplication.java
@@ -0,0 +1,13 @@
+package io.dapr.springboot.examples.consumer;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class ConsumerApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ConsumerApplication.class, args);
+ }
+
+}
diff --git a/spring-boot-examples/consumer-app/src/main/java/io/dapr/springboot/examples/consumer/Order.java b/spring-boot-examples/consumer-app/src/main/java/io/dapr/springboot/examples/consumer/Order.java
new file mode 100644
index 000000000..f556d5b08
--- /dev/null
+++ b/spring-boot-examples/consumer-app/src/main/java/io/dapr/springboot/examples/consumer/Order.java
@@ -0,0 +1,46 @@
+package io.dapr.springboot.examples.consumer;
+
+public class Order {
+ private String id;
+ private String item;
+ private Integer amount;
+
+ public Order() {
+ }
+
+ /**
+ * Creates a new Order.
+ * @param id order id
+ * @param item item reference
+ * @param amount of items in the order
+ */
+ public Order(String id, String item, Integer amount) {
+ this.id = id;
+ this.item = item;
+ this.amount = amount;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getItem() {
+ return item;
+ }
+
+ public void setItem(String item) {
+ this.item = item;
+ }
+
+ public Integer getAmount() {
+ return amount;
+ }
+
+ public void setAmount(Integer amount) {
+ this.amount = amount;
+ }
+}
diff --git a/spring-boot-examples/consumer-app/src/main/java/io/dapr/springboot/examples/consumer/SubscriberRestController.java b/spring-boot-examples/consumer-app/src/main/java/io/dapr/springboot/examples/consumer/SubscriberRestController.java
new file mode 100644
index 000000000..d3416f147
--- /dev/null
+++ b/spring-boot-examples/consumer-app/src/main/java/io/dapr/springboot/examples/consumer/SubscriberRestController.java
@@ -0,0 +1,36 @@
+package io.dapr.springboot.examples.consumer;
+
+import io.dapr.Topic;
+import io.dapr.client.domain.CloudEvent;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RestController
+public class SubscriberRestController {
+
+ private List events = new ArrayList<>();
+
+ /**
+ * Subscribe to cloud events.
+ * @param cloudEvent payload
+ */
+ @PostMapping("subscribe")
+ @Topic(pubsubName = "pubsub", name = "topic")
+ public void subscribe(@RequestBody CloudEvent cloudEvent) {
+ System.out.println("CONSUME +++++ " + cloudEvent);
+ System.out.println("ORDER +++++ " + cloudEvent.getData());
+ events.add(cloudEvent);
+ }
+
+ @GetMapping("events")
+ public List getAllEvents() {
+ return events;
+ }
+
+}
+
diff --git a/spring-boot-examples/consumer-app/src/main/resources/application.properties b/spring-boot-examples/consumer-app/src/main/resources/application.properties
new file mode 100644
index 000000000..fa29657d1
--- /dev/null
+++ b/spring-boot-examples/consumer-app/src/main/resources/application.properties
@@ -0,0 +1,2 @@
+spring.application.name=consumer-app
+server.port=8081
diff --git a/spring-boot-examples/consumer-app/src/test/java/io/dapr/springboot/examples/consumer/ConsumerAppTestConfiguration.java b/spring-boot-examples/consumer-app/src/test/java/io/dapr/springboot/examples/consumer/ConsumerAppTestConfiguration.java
new file mode 100644
index 000000000..57c8b8b7f
--- /dev/null
+++ b/spring-boot-examples/consumer-app/src/test/java/io/dapr/springboot/examples/consumer/ConsumerAppTestConfiguration.java
@@ -0,0 +1,18 @@
+package io.dapr.springboot.examples.consumer;
+
+import io.dapr.client.DaprClient;
+import io.dapr.spring.boot.autoconfigure.pubsub.DaprPubSubProperties;
+import io.dapr.spring.messaging.DaprMessagingTemplate;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@EnableConfigurationProperties({DaprPubSubProperties.class})
+public class ConsumerAppTestConfiguration {
+ @Bean
+ public DaprMessagingTemplate messagingTemplate(DaprClient daprClient,
+ DaprPubSubProperties daprPubSubProperties) {
+ return new DaprMessagingTemplate<>(daprClient, daprPubSubProperties.getName(), false);
+ }
+}
diff --git a/spring-boot-examples/consumer-app/src/test/java/io/dapr/springboot/examples/consumer/ConsumerAppTests.java b/spring-boot-examples/consumer-app/src/test/java/io/dapr/springboot/examples/consumer/ConsumerAppTests.java
new file mode 100644
index 000000000..fc4a1538b
--- /dev/null
+++ b/spring-boot-examples/consumer-app/src/test/java/io/dapr/springboot/examples/consumer/ConsumerAppTests.java
@@ -0,0 +1,64 @@
+package io.dapr.springboot.examples.consumer;
+
+import io.dapr.spring.messaging.DaprMessagingTemplate;
+import io.dapr.springboot.DaprAutoConfiguration;
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.io.IOException;
+import java.time.Duration;
+
+import static io.restassured.RestAssured.given;
+import static org.awaitility.Awaitility.await;
+import static org.hamcrest.CoreMatchers.equalTo;
+
+
+@SpringBootTest(classes = {TestConsumerApplication.class, DaprTestContainersConfig.class,
+ ConsumerAppTestConfiguration.class, DaprAutoConfiguration.class},
+ webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
+class ConsumerAppTests {
+
+ @Autowired
+ private DaprMessagingTemplate messagingTemplate;
+
+ @Autowired
+ private SubscriberRestController subscriberRestController;
+
+ @BeforeAll
+ public static void setup() {
+ org.testcontainers.Testcontainers.exposeHostPorts(8081);
+ }
+
+ @BeforeEach
+ void setUp() {
+ RestAssured.baseURI = "http://localhost:" + 8081;
+ }
+
+
+ @Test
+ void testMessageConsumer() throws InterruptedException, IOException {
+
+ messagingTemplate.send("topic", new Order("abc-123", "the mars volta LP", 1));
+
+
+ given()
+ .contentType(ContentType.JSON)
+ .when()
+ .get("/events")
+ .then()
+ .statusCode(200);
+
+
+ await()
+ .atMost(Duration.ofSeconds(5))
+ .until(subscriberRestController.getAllEvents()::size, equalTo(1));
+
+
+ }
+
+}
diff --git a/spring-boot-examples/consumer-app/src/test/java/io/dapr/springboot/examples/consumer/DaprTestContainersConfig.java b/spring-boot-examples/consumer-app/src/test/java/io/dapr/springboot/examples/consumer/DaprTestContainersConfig.java
new file mode 100644
index 000000000..7eaa13a7b
--- /dev/null
+++ b/spring-boot-examples/consumer-app/src/test/java/io/dapr/springboot/examples/consumer/DaprTestContainersConfig.java
@@ -0,0 +1,78 @@
+package io.dapr.springboot.examples.consumer;
+
+import io.dapr.testcontainers.Component;
+import io.dapr.testcontainers.DaprContainer;
+import io.dapr.testcontainers.DaprLogLevel;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
+import org.springframework.context.annotation.Bean;
+import org.testcontainers.DockerClientFactory;
+import org.testcontainers.containers.Network;
+import org.testcontainers.containers.RabbitMQContainer;
+import org.testcontainers.utility.DockerImageName;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@TestConfiguration(proxyBeanMethods = false)
+public class DaprTestContainersConfig {
+
+ @Bean
+ public Network getDaprNetwork() {
+ Network defaultDaprNetwork = new Network() {
+ @Override
+ public String getId() {
+ return "dapr-network";
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return null;
+ }
+ };
+
+ List networks = DockerClientFactory.instance().client().listNetworksCmd()
+ .withNameFilter("dapr-network").exec();
+ if (networks.isEmpty()) {
+ Network.builder().createNetworkCmdModifier(cmd -> cmd.withName("dapr-network")).build().getId();
+ return defaultDaprNetwork;
+ } else {
+ return defaultDaprNetwork;
+ }
+ }
+
+ @Bean
+ public RabbitMQContainer rabbitMQContainer(Network daprNetwork) {
+ return new RabbitMQContainer(DockerImageName.parse("rabbitmq:3.7.25-management-alpine"))
+ .withExposedPorts(5672).withNetworkAliases("rabbitmq").withReuse(true).withNetwork(daprNetwork);
+
+ }
+
+ @Bean
+ @ServiceConnection
+ public DaprContainer daprContainer(Network daprNetwork, RabbitMQContainer rabbitMQContainer) {
+
+ Map rabbitMqProperties = new HashMap<>();
+ rabbitMqProperties.put("connectionString", "amqp://guest:guest@rabbitmq:5672");
+ rabbitMqProperties.put("user", "guest");
+ rabbitMqProperties.put("password", "guest");
+
+ return new DaprContainer("daprio/daprd:1.14.4").withAppName("consumer-app")
+ .withNetwork(daprNetwork).withComponent(new Component("pubsub",
+ "pubsub.rabbitmq", "v1", rabbitMqProperties))
+ .withDaprLogLevel(DaprLogLevel.DEBUG)
+ .withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
+ .withAppPort(8081).withAppChannelAddress("host.testcontainers.internal")
+ .withReusablePlacement(true).dependsOn(rabbitMQContainer);
+ }
+
+
+}
diff --git a/spring-boot-examples/consumer-app/src/test/java/io/dapr/springboot/examples/consumer/TestConsumerApplication.java b/spring-boot-examples/consumer-app/src/test/java/io/dapr/springboot/examples/consumer/TestConsumerApplication.java
new file mode 100644
index 000000000..d616b3b71
--- /dev/null
+++ b/spring-boot-examples/consumer-app/src/test/java/io/dapr/springboot/examples/consumer/TestConsumerApplication.java
@@ -0,0 +1,19 @@
+package io.dapr.springboot.examples.consumer;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+
+@SpringBootApplication
+public class TestConsumerApplication {
+
+ public static void main(String[] args) {
+ org.testcontainers.Testcontainers.exposeHostPorts(8081);
+ SpringApplication
+ .from(ConsumerApplication::main)
+ .with(DaprTestContainersConfig.class)
+ .run(args);
+ }
+
+
+}
diff --git a/spring-boot-examples/consumer-app/src/test/resources/application.properties b/spring-boot-examples/consumer-app/src/test/resources/application.properties
new file mode 100644
index 000000000..212a88a83
--- /dev/null
+++ b/spring-boot-examples/consumer-app/src/test/resources/application.properties
@@ -0,0 +1,2 @@
+dapr.pubsub.name=pubsub
+server.port=8081
\ No newline at end of file
diff --git a/spring-boot-examples/pom.xml b/spring-boot-examples/pom.xml
index ef0c2d4d3..a7c685935 100644
--- a/spring-boot-examples/pom.xml
+++ b/spring-boot-examples/pom.xml
@@ -15,6 +15,7 @@
producer-app
+ consumer-app
\ No newline at end of file