Caching MessageHandlerInvoker

Is there a way to cache the MessageHandlerInvoker?
It looks like Axon 2.0 creates a new instance of MessageHandlerInvoker for each event.
This in turn scans for annotations each time making it slow and wasteful.

Hi Ming,

unless I am really looking at the wrong thing here, the MessageHandlerInvoker is created only once for each Event Listener instance. At creation time, it will inspect the annotations and from there on will use classes that don’t require reflection anymore.

A small benchmark shows that I can still do 1 million command per second on an aggregate that has annotated event handlers. So I’m sure there’s nothing absurdly slow about it :wink:

Cheers,

Allard

Hmm.
I’m profiling in JProfiler and it shows that part of the code as the hotspot.
Maybe something wrong with my code.
Let dig deeper.

Are you profiling using instrumentation or sampling?

Instrumentation

Below is a stack trace that shows the problem.
I have an Order entity that extend from AbstractAnnotedAggregateRoot.
The constructor, line 55 creates a new AnnotationventHandlerInvoker and eventually a new MessageHandlerInvoker for each instance

at org.axonframework.common.annotation.MessageHandlerInvoker.(MessageHandlerInvoker.java:42)
at org.axonframework.eventhandling.annotation.AnnotationEventHandlerInvoker.(AnnotationEventHandlerInvoker.java:48)
at org.axonframework.eventsourcing.annotation.AbstractAnnotatedAggregateRoot.(AbstractAnnotatedAggregateRoot.java:55)
at axon.orders.Order.(Order.java:35)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(NativeConstructorAccessorImpl.java:-1)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at org.axonframework.commandhandling.annotation.ConstructorCommandMessageHandler.invoke(ConstructorCommandMessageHandler.java:105)
at org.axonframework.commandhandling.annotation.AggregateAnnotationCommandHandler$AnnotatedConstructorCommandHandler.handle(AggregateAnnotationCommandHandler.java:167)
at org.axonframework.commandhandling.DefaultInterceptorChain.proceed(DefaultInterceptorChain.java:62)
at org.axonframework.commandhandling.DefaultInterceptorChain.proceed(DefaultInterceptorChain.java:68)
at org.axonframework.commandhandling.SimpleCommandBus.doDispatch(SimpleCommandBus.java:118)
at org.axonframework.commandhandling.SimpleCommandBus.dispatch(SimpleCommandBus.java:79)

Ah, it’s instantiated once per aggregate instande. You’re right that the annotation and method inspection only needs to be done once per class, and can be cached for several instances.

Can you file an issue for this? I don’t have access to proper internet right now (just a mobile phone) and I’m afraid I’ll forget.

Good find!
Cheers,

Allard