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 ParameterResolverand the ParameterResolverFactory(see Figure 1).

Figure 1 - ParameterResolverFactory and ParameterResolver interfaces

The ParameterResolverFactoryis 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 ParameterResolverFactoriesand to delegate the creation of a specific ParameterResolverto 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 ParameterResolverFactorycan be configured using the Axon Configurer. The ClasspathParameterResolverFactory(not an implementation of ParameterResolverFactory) is a default way of providing ParameterResolverFactoriesto 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 ParameterResolverFactoriesprovided by the framework.

Figure 2 - Parameter Resolver Factories provided by Axon Framework

The DefaultParameterResolverFactoryis 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

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 Userevents handled by event-handling components, and for most of them, you’d need a Userentity. We could do it by querying the UserRepositoryin 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 UserRepositorywhen 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.