Files
spring-messaging-demo/rabbitmq/docs/02-exchanges.md
2026-08-29 10:30:21 +05:30

3.2 KiB

← The on-ramp · Module README · The silent drop →

2. Four exchange types

A producer never publishes to a queue. It publishes to an exchange with a routing key, and bindings decide where that lands. The whole topology is in Topology.java as beans; RabbitAdmin declares them when the connection opens.

Direct — exact match

Binding key new receives routing key new. Nothing else. This is the workhorse: one queue per command type.

Fanout — routing key ignored entirely

Every bound queue gets a copy. audit.all and analytics.all both receive it, and the routing key you passed is not consulted at all. Use it for broadcast; use it knowing that adding a queue adds a full copy of the traffic.

Topic — wildcards over dot-separated words

* is exactly one word. # is zero or more. The distinction is the one people get wrong, so here it is against a real broker (docs/output/topic-wildcards.txt):

routing key              orders.eu    orders.high  note
order.eu.high            true         true         matches both
order.eu.low             true         false        matches order.eu.* only
order.us.high            false        true         matches order.#.high only
order.eu.west.high       false        true         matches order.#.high only - * is one word
order.high               false        true         matches order.#.high - # can be zero words

Bindings are order.eu.* and order.#.high. Two rows are worth pausing on:

  • order.eu.west.high does not match order.eu.*, because * matches one word and west.high is two. Regex intuition says otherwise.
  • order.high does match order.#.high, because # matches zero words. So a binding you wrote to mean "something in the middle" also matches "nothing in the middle".

Design routing keys most-general-to-most-specific (order.eu.west.high, not high.order.eu.west), because # and * work left to right and a hierarchy you can bind usefully is one that starts broad.

Headers — match a map, ignore the routing key

x-match=all requires every named header to be present and equal. x-match=any requires one. From RoutingTest:

Message headers x-match=all queue x-match=any queue
priority=high, region=eu yes yes
priority=high no yes
priority=high, region=us no yes

The third row is the one to remember: all matches on value, not on presence. A header that is there with the wrong value fails the same way a missing one does.

Headers exchanges are slower than topic exchanges and much less common. Reach for them when the routing criteria are genuinely multi-dimensional and do not compose into a hierarchy.

The default exchange

Publishing to the empty exchange name "" routes by queue name, using the routing key as the queue name. Every queue is implicitly bound to it. That is how convertAndSend("", "orders.work", message) works, and it is the one piece of AMQP that behaves like a magic constant.

The silent drop →