[#3485] Add annotated and declarative handler interceptor support for events, commands, and queries#4515
Conversation
Adds intercepted() to CompletePhase, enabling MessageHandlerInterceptors to be applied to all event handling components in a configurer. Calling intercepted() closes the component registration phase; subsequent calls accumulate interceptors in registration order.
Adds a third interceptor registration scope to the event handler interceptors section: per-configurer, via intercepted() on EventHandlingComponentsConfigurer. Also fixes a typo in the existing per-processor example (withInterceptr).
…eptors section Resolves #3485
# Conflicts: # messaging/src/main/java/org/axonframework/messaging/core/IgnoredEntriesMessageStream.java # messaging/src/main/java/org/axonframework/messaging/core/MessageStream.java
Therefore, the test for interceptors must not assume that the resulting stream should be consumed before a handler is invoked.
|
Relates to #3485 |
…n support Extends the annotated handler interceptor mechanism (already present for events) to command and query handling components. Adds declarative interceptor support to CommandHandlingModule and QueryHandlingModule, mirroring the existing EventHandlingComponentsConfigurer.intercepted() API.
- Enable component-message-intercepting and annotated-exception-handling in nav - Replace annotated-exception-handling.adoc WARNING placeholder with real content - Replace "not yet supported" section in migration guide with migration examples for @CommandHandlerInterceptor, @EventHandlerInterceptor, @QueryHandlerInterceptor, and @ExceptionHandler
smcvb
left a comment
There was a problem hiding this comment.
I am most doubtful about the use of the payloadType on the annotations. Should we still do that? Furthermore, I see an (I assume) accidental mix of #3485 and #3062 in this PR. I'd expect any @ExceptionHandler logic to be part of the other PR (#4520) that you've created. Lastly, I am missing tests for the @MessageHandlerInterceptor in this renewed setup.
Removed payloadType support from interceptors. Although present on handlers, it is somewhat confusing on interceptors, as they inherently address messages of different types. Changed ordering of interceptor sections to Command -> Event -> Query.
Remove the @ExceptionHandler test, documentation, and migration guide content that belongs in the @ExceptionHandler PR (#3062/#4520), not in the annotated interceptors PR (#3485/#4515). Also add missing @NullMarked package-info.java files for the three new annotation packages introduced for annotated interceptors.
|
I removed the payloadType references from the interceptors. It was misleading at best. I decided to not replace it with a messageName or anything, because interceptors are designed to be crosscutting concerns. If they apply to a specific message type, they should be part of that message's handler. |
|
smcvb
left a comment
There was a problem hiding this comment.
My concerns have been addressed, hence I'm approving this pull request.




Summary
Introduces annotated handler interceptor support for all three message types (events, commands, and queries), plus declarative interceptor registration on the command and query module builder APIs.
Annotated interceptors
Three annotations allow interceptor methods to be declared directly on a handling component class:
@EventHandlerInterceptor— applied before every@EventHandlermethod on the same instance@CommandHandlerInterceptor— applied before every@CommandHandlermethod on the same instance@QueryHandlerInterceptor— applied before every@QueryHandlermethod on the same instanceTwo styles are supported:
Before-interceptor —
voidmethod, no chain parameter; chain auto-proceeds after the method returns normally:Surround-interceptor — returns
MessageStream, declares aMessageHandlerInterceptorChainparameter; the method controls whether and when the chain proceeds:The optional
payloadTypeattribute narrows the interceptor to messages whose payload is assignable to a specific type.The supporting infrastructure (
MessageHandlerInterceptorDefinition,ChainedMessageHandlerInterceptorMember,InterceptorChainParameterResolverFactory,LazyMessageStream,IgnoredEntriesMessageStream) is generic and shared across all three message types.Declarative interceptors
EventHandlingComponentsConfigurer.intercepted(),CommandHandlingModule.CommandHandlerPhase.intercepted(), andQueryHandlingModule.QueryHandlerPhase.intercepted()register aMessageHandlerInterceptoraround the component assembled by the module:Multiple calls accumulate interceptors in registration order. The assembled component is wrapped in the appropriate
Intercepting*HandlingComponentwhen at least one interceptor is registered.Documentation
component-message-intercepting.adochas been rewritten: the placeholder warning is removed, all three annotation types are documented with correct Axon Framework 5 APIs, and a new section covers the declarative module-levelintercepted()approach.This PR resolves #3485.