What standard headers does Spring assign to every message, and what are the consequences of their auto-generation?
answer
- id = UUID, timestamp = Long epoch millis
- IdGenerator, can swap/disable
- copy regenerates id+timestamp
- use correlationId for stable tracking
- timestamp = creation not enqueue time
basics
~10 sSpring auto-assigns id (a unique UUID) and timestamp (creation epoch millis) to every MessageHeaders. You read them via getId()/getTimestamp() but never set them yourself — the framework generates them when the message is built.
solid answer
~40 sEvery MessageHeaders carries two framework-managed headers: id (MessageHeaders.ID) — a java.util.UUID unique per message — and timestamp (MessageHeaders.TIMESTAMP) — a Long epoch-millis capturing creation time. They're generated by an IdGenerator when the MessageHeaders is constructed, and are read-only like all headers. A key consequence: because building a message from an existing one (MessageBuilder.fromMessage(...).build()) creates fresh MessageHeaders, the id and timestamp are regenerated, so a 'copied' message is not identity-equal to the original. If you need stable correlation across transformations you carry your own correlationId header rather than relying on id. Other well-known-but-optional headers include reply-channel, error-channel, and content-type. In high-throughput scenarios UUID generation cost matters, so Spring lets you swap the IdGenerator (e.g., a JVM-scoped simpler generator) or disable id/timestamp generation entirely.
code
java · 9 linesimport org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
Message<String> original = MessageBuilder.withPayload("x").build();
Message<String> copy = MessageBuilder.fromMessage(original).build();
boolean same = original.getHeaders().getId()
.equals(copy.getHeaders().getId());
// same == false: the copy has a freshly generated id (and timestamp)go deeper
Know id and timestamp exist and are auto-set.
Explain the copy-regenerates-id consequence and using correlationId instead.
Discuss IdGenerator swapping/disabling and the performance rationale.
Weigh identity semantics, tracing strategy, and throughput trade-offs of id generation.
## The two always-present headers When a `MessageHeaders` object is created, Spring populates: - **`id`** — key `MessageHeaders.ID` (`"id"`), a `java.util.UUID`, unique to that message instance. Read via `headers.getId()`. - **`timestamp`** — key `MessageHeaders.TIMESTAMP` (`"timestamp"`), a `Long` of `System.currentTimeMillis()` at creation. Read via `headers.getTimestamp()`. Both are **generated by the framework**, not by you, and both are immutable once set. ## Who generates the id? Header id creation goes through an `org.springframework.util.IdGenerator`. The default is a random-UUID generator. Spring exposes hooks to replace it — for example an `AlternativeJdkIdGenerator`, or in messaging configuration you can register a custom `IdGenerator` bean — and even to **disable** id/timestamp generation for performance (UUID creation and time reads add up at very high message rates). ## The identity-regeneration consequence This is the subtle part interviewers probe. Because headers are immutable, 'modifying' a message means building a **new** `MessageHeaders`: ```java Message<String> copy = MessageBuilder.fromMessage(original).build(); // copy.getHeaders().getId() != original.getHeaders().getId() ``` The copy gets a **new id and new timestamp**. So: - **Don't** use `id` as a stable business/correlation key across pipeline stages — it changes on every rebuild. - **Do** propagate your own `correlationId` (Spring Integration provides `IntegrationMessageHeaderAccessor.CORRELATION_ID`) that survives transformations. ## Other well-known headers Optional but standardized (constants on `MessageHeaders` or protocol accessors): - `REPLY_CHANNEL` — request/reply return path. - `ERROR_CHANNEL` — where exceptions route. - `CONTENT_TYPE` — payload MIME type, used by message converters. ## Gotchas - `getId()` returns `UUID` (or null if id generation was disabled) — code defensively if you disable it. - `timestamp` is creation time, **not** send/receive time; don't treat it as a broker enqueue time. - Copying a message for auditing and then comparing ids will always show a mismatch — that's expected, not a bug. - These headers occupy reserved keys; setting `"id"`/`"timestamp"` yourself via `setHeader` is ignored/overridden by the framework's managed values.
- Why shouldn't you use the id header as a correlation key across a pipeline?Every rebuilt/transformed message gets a new id, so it won't stay constant. Carry an explicit correlationId header instead.
- Can you turn off id/timestamp generation?Yes — you can supply a custom or disabled IdGenerator (e.g. via messaging configuration) to reduce per-message UUID/clock overhead in high-throughput systems.
saying these in an interview costs you the question
- Thinking the id survives message copies/transformations
- Treating timestamp as broker enqueue/receive time
- Believing you set id/timestamp manually