Axon issue with Spring AOP

Hi,

I have noticed in my project that we cannot use Spring AOP and Axon Framework together inside an Aggregate. Maybe we are doing something in an incorrect way, so if anybody could advise me, I would be really happy.

What I mean by “cannot use” is - if there we try to use a Spring AOP aspect on a @CommandHandler method, the following error will popup even though we have well initialized the aggregate and set the identifier in the command.

org.axonframework.eventsourcing.IncompatibleAggregateException: Aggregate identifier must be non-null after applying an event. Make sure the aggregate identifier is initialized at the latest when handling the creation event.

We use AOP for our custom validation on the command - workaround for this is to move the @CommandHandler method to a separate class and load the aggregate via a repository, but that causes performance issues.

I’ve prepared a very simple project that illustrates this problem - https://github.com/ultcyber/axon-demo-aop.

It is a Spring Boot 2 Web application - the way to reproduce the issue is to (excuse me for non-restful endpoints :wink: ):

  1. Create an aggregate via POST This will return the ID of the aggregate in point 2.
  2. Send a POST request to

This will result in the beforementioned error. If you take a look at the aggregate (DemoAggregate) there is an annotation @TestAnnotation which marks a method to be used by DemoAspect class to just print out the JoinPoint arguments.

If you remove the @TestAnnotation - all works without issues.

If someone could advise on this, I would be really grateful.

Hi Mateusz,

As far as my Spring AOP knowledge goes, it only works on Spring-managed Beans.
Additionally, your Aggregate is not a Spring Managed Bean under the regular terms.
Hence I would expect Spring AOP to not take effect on your Aggregate.

If you want to introduce cross-cutting concerns on Message Handler annotated methods when using Axon, I suggest to take a look at Axon’s HandlerEnhancer and HandlerEnhancerDefinition set up.
It’s this mechanism which the framework uses to add the functionality to for example now how to start a saga with the @StartSaga annotation for a Saga Event Handler.

There’s a page on this in the Reference Guide (which you can find here) further specifying this idea.

This HandlerEnhancer/HandlerEnhancerDefinition approach gives you very fine grained control over what you’d want to do on message handling functions.
If you however want to (relatively) generic command message structural validation, I’d suggest to use Axon’s MessageDispatchInterceptor and MessageHandlerInterceptor logic.
For specifics on these concepts, I’d suggest to read this page of the Reference Guide.

Hope this sheds some light on your options Mateusz!

Cheers,
Steven

Hi Steven,

Thanks for taking time to respond.

I think Aggregates should normally register themselves as Spring-managed beans as @Aggregate annotation includes @Component. I’ve spent some time debugging the issue and it looks like the AnnotatedAggregate class when invoking:
@Override public Object identifier() { return inspector.getIdentifier(aggregateRoot); }

the “aggregateRoot” will be a Spring AOP CGLib proxy that for some reason does have the id field set as “null”, hence the error.

Could not determine why the proxy does not have an “id” - maybe, as this is an EventSourced aggregate, then the proxy might be created before the proxied object gets sourced (hence initially it copies the “null” value of the field).

But, as you mentioned, maybe there exist more dedicated solutions for doing what we try to achieve. I will take a look at the examples you have provided. Thank you!

Cheers,
Mateusz

W dniu środa, 2 października 2019 12:09:58 UTC+2 użytkownik Steven van Beelen napisał:

Hi Mateusz,

I agree it’s not overly clear in this area.
I’ve seen this exact issue you’ve encountered before, think we should be more wordy around this.

We are always looking to improve the framework of course, so some approach to make it more like a regular Spring managed bean might be in place.
This will require some internal discussions from our end, whether we feel this would be justified over the current set up, with Parameter Resolvers for auto-wiring Spring Beans in your message handling functions and the aforementioned HandlerEnhancer(Definition) set up to cover for the AOP example.

Concluding, let us know whether the shared sample in the Reference Guide is sufficient for your use case.
We are always happy to help, thus do not hesitate if you have further question.

Cheers,

Steven van Beelen

Axon Framework Lead Developer

AxonIQ

twitter-icon_128x128.png