diff --git a/README.adoc b/README.adoc
index fe90c74b..55e4892a 100644
--- a/README.adoc
+++ b/README.adoc
@@ -79,6 +79,9 @@ There are several modules in Spring for Apache Pulsar. Here is a quick overview:
=== spring-pulsar
The main library that provides the API to access Apache Pulsar.
+=== spring-pulsar-bom
+Provides a Maven BOM (https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#bill-of-materials-bom-poms[Bill of Materials]) that recommends a consistent version for all Spring for Apache Pulsar published modules.
+
=== spring-pulsar-cache-provider
Provides the interfaces for the cache provider used by the main library to cache producers.
diff --git a/settings.gradle b/settings.gradle
index fd330fe2..75a495ce 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -13,6 +13,7 @@ plugins {
}
include 'spring-pulsar'
+include 'spring-pulsar-bom'
include 'spring-pulsar-cache-provider'
include 'spring-pulsar-cache-provider-caffeine'
include 'spring-pulsar-reactive'
diff --git a/spring-pulsar-bom/spring-pulsar-bom.gradle b/spring-pulsar-bom/spring-pulsar-bom.gradle
new file mode 100644
index 00000000..2ee40951
--- /dev/null
+++ b/spring-pulsar-bom/spring-pulsar-bom.gradle
@@ -0,0 +1,20 @@
+import org.springframework.pulsar.gradle.SpringModulePlugin
+
+plugins {
+ id 'org.springframework.pulsar.spring-module'
+}
+
+description = 'Spring Pulsar (Bill of Materials)'
+
+dependencies {
+ constraints {
+ project.rootProject.subprojects
+ .sort { "$it.name" }
+ .findAll { it.name != "spring-pulsar-bom" }
+ .each { p ->
+ p.plugins.withType(SpringModulePlugin) {
+ api p
+ }
+ }
+ }
+}
diff --git a/spring-pulsar-docs/src/main/antora/modules/ROOT/nav.adoc b/spring-pulsar-docs/src/main/antora/modules/ROOT/nav.adoc
index 327cbb51..cfd1c3ff 100644
--- a/spring-pulsar-docs/src/main/antora/modules/ROOT/nav.adoc
+++ b/spring-pulsar-docs/src/main/antora/modules/ROOT/nav.adoc
@@ -17,5 +17,6 @@
* Appendices
** xref:appendix/version-compatibility.adoc[]
** xref:appendix/override-boot-dependencies.adoc[]
+** xref:appendix/getting-dependencies-without-boot.adoc[]
** xref:appendix/non-ga-versions.adoc[]
** xref:appendix/native-image.adoc[]
diff --git a/spring-pulsar-docs/src/main/antora/modules/ROOT/pages/appendix/getting-dependencies-without-boot.adoc b/spring-pulsar-docs/src/main/antora/modules/ROOT/pages/appendix/getting-dependencies-without-boot.adoc
new file mode 100644
index 00000000..84d667c8
--- /dev/null
+++ b/spring-pulsar-docs/src/main/antora/modules/ROOT/pages/appendix/getting-dependencies-without-boot.adoc
@@ -0,0 +1,119 @@
+[[deps-without-boot]]
+= Getting Dependencies without Spring Boot
+
+We recommend a Spring Boot first approach when using Spring for Apache Pulsar.
+However, if you do not use Spring Boot, the preferred way to get the dependencies is to use the provided BOM to ensure a consistent version of modules is used throughout your entire project.
+The following example shows how to do so for both Maven and Gradle:
+
+[tabs]
+======
+Maven::
++
+.pom.xml
+[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
+----
+
+
+
+
+ org.springframework.pulsar
+ spring-pulsar-bom
+ {spring-pulsar-version}
+ pom
+ import
+
+
+
+----
+
+Gradle::
++
+.build.gradle
+[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
+----
+plugins {
+ id "io.spring.dependency-management" version "1.1.4"
+}
+
+dependencyManagement {
+ imports {
+ mavenBom 'org.springframework.pulsar:spring-pulsar-bom:{spring-pulsar-version}'
+ }
+}
+----
+======
+
+A minimal Spring for Apache Pulsar set of dependencies typically looks like the following:
+
+[tabs]
+======
+Maven::
++
+.pom.xml
+[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
+----
+
+
+
+ org.springframework.pulsar
+ spring-pulsar
+
+
+----
+
+Gradle::
++
+.build.gradle
+[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
+----
+dependencies {
+ implementation "org.springframework.pulsar:spring-pulsar"
+}
+----
+======
+
+If you use additional features (such as Reactive), you need to also include the appropriate dependencies.
+
+Spring for Apache Pulsar builds against Spring Framework {spring-framework-version} but should generally work with any newer version of Spring Framework 6.x.
+Many users are likely to run afoul of the fact that Spring for Apache Pulsar's transitive dependencies resolve Spring Framework {spring-framework-version}, which can cause strange classpath problems.
+The easiest way to resolve this is to use the `spring-framework-bom` within your `dependencyManagement` section as follows:
+
+[tabs]
+======
+Maven::
++
+.pom.xml
+[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
+----
+
+
+
+
+ org.springframework
+ spring-framework-bom
+ {spring-framework-version}
+ pom
+ import
+
+
+
+----
+
+Gradle::
++
+.build.gradle
+[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
+----
+plugins {
+ id "io.spring.dependency-management" version "1.1.4"
+}
+
+dependencyManagement {
+ imports {
+ mavenBom 'org.springframework:spring-framework-bom:{spring-framework-version}'
+ }
+}
+----
+======
+
+The preceding example ensures that all the transitive dependencies of Spring for Apache Pulsar use the Spring {spring-framework-version} modules.
diff --git a/spring-pulsar-reactive/src/test/java/org/springframework/pulsar/reactive/listener/ReactivePulsarListenerTombstoneTests.java b/spring-pulsar-reactive/src/test/java/org/springframework/pulsar/reactive/listener/ReactivePulsarListenerTombstoneTests.java
index 5a1a6194..780f40f9 100644
--- a/spring-pulsar-reactive/src/test/java/org/springframework/pulsar/reactive/listener/ReactivePulsarListenerTombstoneTests.java
+++ b/spring-pulsar-reactive/src/test/java/org/springframework/pulsar/reactive/listener/ReactivePulsarListenerTombstoneTests.java
@@ -238,8 +238,8 @@ class ReactivePulsarListenerTombstoneTests extends ReactivePulsarListenerTestsBa
var pulsarProducerFactory = new DefaultPulsarProducerFactory(pulsarClient);
var fooPulsarTemplate = new PulsarTemplate<>(pulsarProducerFactory);
sendTestMessages(fooPulsarTemplate, TOPIC, Schema.JSON(Foo.class), Foo::new);
- assertThat(latchWithHeaders.await(5, TimeUnit.SECONDS)).isTrue();
- assertThat(latchWithoutHeaders.await(5, TimeUnit.SECONDS)).isTrue();
+ assertThat(latchWithHeaders.await(10, TimeUnit.SECONDS)).isTrue();
+ assertThat(latchWithoutHeaders.await(10, TimeUnit.SECONDS)).isTrue();
assertMessagesReceivedWithHeaders(receivedMessagesWithHeaders, Foo::new);
assertMessagesReceivedWithoutHeaders(receivedMessagesWithoutHeaders, Foo::new);
}