Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Parameter Resolvers in Axon

DZone 's Guide to

Parameter Resolvers in Axon

Axon provides a really powerful mechanism to inject these dependencies into message handlers — Parameter Resolvers.

· Java Zone ·
Free Resource

Axon is an open-source Java framework for building systems in CQRS (Command Query Responsibility Segregation), DDD (Domain Driven Design), and Event Sourcing manner. Axon provides a high level of location transparency, which gives the opportunity to easily split the system into several microservices. You can download the fully open-source package here. The Axon Framework consists of message-based commands, events, and queries that are supported types of messages. For each of these messages, we can define a handler (a method or constructor) to handle it. In some cases, the message itself has enough information to be handled, but in many others, we have a dependency on other components and/or variables (message metadata such as correlation information would be a good example). Axon provides a really powerful mechanism to inject these dependencies into message handlers — Parameter Resolvers. This is the story about them. At the end of this article, you can find a cheat sheet of all resolvers provided by the Axon Framework.

Anatomy

There are two important components that support this mechanism: the  ParameterResolver and the  ParameterResolverFactory (see Figure 1).

Figure 1 - ParameterResolverFactory and ParameterResolver interfaces

Figure 1 - ParameterResolverFactory and ParameterResolver interfaces

The  ParameterResolverFactory is used to create instances of the ParameterResolvers. Axon does an inspection of messaging handling members (such as command handlers, event handlers, and query handlers) using reflection. For each of these handlers, we iterate through its parameter list and try to find (using the  ParameterResolverFactory) the corresponding  ParameterResolver, which can resolve the given parameter. Just before handling a concrete message, we resolve the message handler parameters using previously created resolvers. This is how the injection of specific fields and components into message handlers is done in Axon.

Wiring

There is an implementation of the  ParameterResolverFactory, which is called  MultiParameterResolverFactory. It is used to hold an array of  ParameterResolverFactories and to delegate the creation of a specific ParameterResolver to them.

Service Loader is an out-of-the-box Java API, which offers a specific form of Inversion of Control. It is designed to locate implementation classes of an interface on the classpath. This setup allows us to discover which available implementations of an interface are available on the classpath at runtime, and thus, it paves the way for modules designed around a clean separation between an API module and multiple implementation modules. It’s implemented as a file located in the META-INF/services folder of a JAR. The name of the file is the fully qualified name of the interface, while its content is a slit of qualified names of available implementations.

The  ParameterResolverFactory can be configured using the Axon Configurer. The  ClasspathParameterResolverFactory  (not an implementation of  ParameterResolverFactory) is a default way of providing  ParameterResolverFactories to the framework using the Service Loader mechanism to load all available implementations. All implementations are wrapped in the  MultiParameterResolverFactory. This is also an extension point providing framework users with the means of defining their own  ParameterResolverFactories.

Parameter Resolver Cheat Sheet

Figure 2 shows all  ParameterResolverFactories provided by the framework.


Figure 2 - Parameter Resolver Factories provided by Axon Framework

Figure 2 - Parameter Resolver Factories provided by Axon Framework

The  DefaultParameterResolverFactory is used to create:

  • a  PayloadParameterResolver: resolves the payload of a message

  • a  MessageParameterResolver: resolves the message as a whole

  • a  MetaDataParameterResolver: resolves the key-value map of metadata values attached to a message

  • an AnnotatedMetaDataParameterResolver: resolves specific metadata value based on the provided key

Certain parameters are annotated, hence the  AbstractAnnotatedParameterResolverFactory. Corresponding factories are:

  • The  SequenceNumberParameterResolverFactory, which creates a  SequenceNumberParameterResolver that is used to resolve sequence number of domain events (events that are published by an aggregate)

    @EventSourcingHandler
    public void on(MyEvent event, @SequenceNumber long sequenceNumber) {   
        // handle domain event
    }

  • The  TimestampParameterResolverFactory, which creates a TimestampParameterResolver that is used to resolve the timestamp of an event message.

    @EventHandler
    public void on(MyEvent event, @Timestamp Instant timestamp) {
        // handle event
    }
     

  • The  MessageIdentifierParameterResolverFactory creates a  MessageIdentifierParameterResolver used to resolve the identifier of a message (command, event, query, etc.).

    @MessageHandler
    public void handle(Message message, @MessageIdentifier String messageIdentifier) {
        // handle message
    }
     

  • The ConcludesBatchParameterResolverFactory  creates a  ConcludesBatchParameterResolver used to resolve whether the given event is the last one in the batch of events being processed.

    @EventHandler
    public void on(MyEvent event, @ConcludesBatch Boolean concludesBatch) {
        // handle event
    }
     

Besides the aforementioned resolvers, there are many more (shown in Figure 2) which, as they are self-explanatory, will not be treated in detail here. Of course, we can always implement our own Parameter Resolvers if necessary.

One example could be to have query model entity ready during event processing. Think of the case where you have all kinds of  User events handled by event-handling components, and for most of them, you’d need a User entity. We could do it by querying the UserRepository in those event handlers, which is not important to our business case and just pollutes the logic. The other approach could be to create a  UserParameterResolver, which would query the  UserRepository when User event comes along and have a User ready to be injected as a parameter to our handler.

Conclusion

While most of the resources needed to handle a certain message can be obtained by different means, Parameter Resolvers provide an elegant way of doing so. You don’t have to write all of the boiler-plate code to extract certain metadata values, to get the information whether your event handler is invoked for replaying purposes or to get sequence number of your events, you just need to declare what you need as a parameter in your message handler and (if available) Parameter Resolver will resolve the value for you. In the end, all you have to worry about is your business case.

Topics:
axon framework ,domain driven design ,cqrs ,event sourcing ,java ,axon ,parameter resolver

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}