# evidence 256 — messaging-provider-selection-and-rabbit-transport # revision: a24ece9cf797f7ea647e33bf846b115208ed1ba5 # cwd: /shared/codebase/clean-architecture-backend-template/src/messaging # command: sed -n "1,80p" messaging-spring-boot-starter/src/main/java/dev/caskeleton/messaging/autoconfigure/MessagingProviderSelection.java; echo; echo ---RabbitChannelPublisher implementations---; grep -rn "implements RabbitChannelPublisher" --include=*.java .; echo "(no matches == no implementation anywhere)"; echo; echo ---MessagingTransport beans in the starter---; grep -rn "MessagingTransport" messaging-spring-boot-starter/src/main/java/dev/caskeleton/messaging/autoconfigure/RabbitMessagingAutoConfiguration.java messaging-spring-boot-starter/src/main/java/dev/caskeleton/messaging/autoconfigure/KafkaMessagingAutoConfiguration.java; echo; echo ---support-matrix.md Rabbit row---; grep -n "RabbitMQ" ../../docs/messaging/support-matrix.md | head -5 # ---- raw output ---- package dev.caskeleton.messaging.autoconfigure; import java.util.List; import java.util.Map; import org.springframework.context.EnvironmentAware; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotationMetadata; import org.springframework.util.ClassUtils; /** * Selects exactly one transport, from a closed registry, by name (MSG-INT-004). * *
Selection used to be {@code @ConditionalOnClass}: Kafka assembled because a Kafka class was on * the classpath and Rabbit because a Rabbit class was, so an application with both libraries — one * transitive dependency is enough — assembled both and published through whichever bean won a * {@code @ConditionalOnMissingBean} race. Nothing failed; the message simply went somewhere nobody * chose. * *
Three outcomes are startup errors now rather than silences: * *
The provider configurations carry no condition of their own any more. Each is reached only
* along the path this class chose, which is what makes "which transport is active" answerable by
* reading one property rather than by resolving a dependency graph.
*/
@Configuration(proxyBeanMethods = false)
@Import(MessagingProviderSelection.Selector.class)
public class MessagingProviderSelection {
/** Broker id to the client class that must be present for it to be honoured. */
static final Map Registered is not the same as assemblable. The Rabbit leaf ships its profile validator,
* failure classifier and security configurer, and no transport — the native channel bridge those
* would sit on has only test implementations. Selecting it therefore produced an unsatisfied
* dependency on {@code MessagingTransport} deep inside the core configuration, which tells an
* operator that a bean is missing rather than that the transport they chose is not finished.
*
* Refused here instead, next to the other selection errors, so the message names the state the
* deployment is actually in. An entry leaves this map on the day its transport does exist.
*/
static final Map