axon with Spring 4

Hi All, i’m trying to set up a simple @EventHandler with Spring 4 annotations and i’m not able to receive event into the EventHandler when i trigger a command.
The command is triggered , then i do a apply into the aggregate, the @EventSourcingHandler is triggered but i have a @EventHandler listening to that event and it not called,
I have try to debug the code source for 3 days and i could make it work. I suspect that my agregate repository is not set up properly but i can’t figure out how to do it with spring 4

Any help will be very nice !!! :wink:

there is my configuration :

@Bean @Lazy(false)
public CommandBus commandBus() {
SimpleCommandBus commandBus = new SimpleCommandBus();
return commandBus;
}

@Bean @Lazy(false)
public EventBus eventBus() {
return new SimpleEventBus();
}

@Bean @Lazy(false)
public AnnotationEventListenerBeanPostProcessor annotationEventListenerBeanPostProcessor() {
AnnotationEventListenerBeanPostProcessor processor = new AnnotationEventListenerBeanPostProcessor();
processor.setEventBus(eventBus());
return processor;
}

@Bean @Lazy(false)
public AnnotationCommandHandlerBeanPostProcessor annotationCommandHandlerBeanPostProcessor() {
AnnotationCommandHandlerBeanPostProcessor processor = new AnnotationCommandHandlerBeanPostProcessor();

processor.setCommandBus(commandBus());
return processor;
}

@Bean @Lazy(false)
EventStore eventStore() {
FileSystemEventStore eventStore = new FileSystemEventStore(new SimpleEventFileResolver(new File(“data/evenstore”)));
return eventStore;

}

@Bean(name = “commandGateway”) @Lazy(false)
public CommandGateway commandGateway() {
// the CommandGateway provides a friendlier API to send commands
CommandGateway commandGateway = new DefaultCommandGateway(commandBus());
return commandGateway;

}

Hi,

is the bean with the @EventHandler annotation part of the same Spring application context? I don’t see it mentioned in you configuration.

Also note that the Event Sourcing Handlers of an aggregate are invoked inmediately on aplly(), while Event Handlers (outsode of the aggregate) are invoked when command processing is committed.

Another thing, instead of mentioning the postprocessors explicitly, you can also put an @AnnotationConfig (or …Driven, not sure anymore) on your Spring configuration.

Cheers,

Allard

Thank you very much for the fast response.

So the bean that have @EventHandler is annotated with @Component. I tried also to explicitly declared it into a @Bean but it didn’t changed anything,
i have something like this :

@Component
public class CommandHandler {

@EventHandler
public void handle(PanelContextCreated panelContextCreated) {


}

}

and the aggregate :

public class PanelContext extends AbstractAnnotatedAggregateRoot {

public PanelContext(Integer id, Channel channelHandlerContext) {
apply(new PanelContextCreated(id, channelHandlerContext));

}

@EventSourcingHandler
public void on(PanelContextCreated panelContextCreated){
this.id = panelContextCreated.getId();
this.channel = panelContextCreated.getChannel();
this.panel = new Panel();
}

}

What do you mean by @ AnnotationConfig

I have a setup file annoted with @Configuration but i didn’t really understood what was the alternative way for the postprocessors.

By the way, the command sucessfully commit but i never get the @EventHandler triggered.

Any idea that could help me ?

Could you also show your Repository configuration, as well as the Command Handler for the aggregate?
There is a class called Command Handler, but it is annotated with an @EventHandler.

What I meant with the annotation, is that you can use the org.axonframework.contextsupport.spring.AnnotationDriven annotation on you Spring Context Bean instead of defining the AnnotationCommandHandlerBeanPostProcessor and AnnotationEventListenerBeanPostProcessor explicitly. It makes the configuration a bit easier to understand.

Cheers,

Allard

Thank you very much Allard, i really appreciate you spend some time with me. Spring Configuration of repository : (I commented out because i end up having nothing working properly afterwards event the command handler) I pretty sure the problem is come from there.
If i understood correctly while i was debugging, There is a Unit of Work that call saveagreggates() method which send events notifications to the Event Handler. I think that my respository is not set up properly but how to do it ?

By the way thank you for the note for AnnotationDriven, i didn’t know it ! that really good

`

@Bean @Lazy(false)
public EventSourcingRepository<PanelContext> eventSourcingRepository() {

EventSourcingRepository<PanelContext> repository = new EventSourcingRepository<>(PanelContext.class, eventStore());
repository.setEventBus(eventBus());
return repository;
}
``
// @Bean @Lazy(false)
// public AggregateAnnotationCommandHandler<PanelContext> commandHandler() {
// return AggregateAnnotationCommandHandler.subscribe(PanelContext.class, eventSourcingRepository(), commandBus());
// }
//
// @Bean @Lazy(false)
// public AnnotationEventListenerAdapter eventHandler() {
// return AnnotationEventListenerAdapter.subscribe(CommandHandler, eventBus());
// }

`

My Spring Config File entirely :

`

`

  • afficher le texte des messages précédents -
    `

@Bean @Lazy(false)
public EventSourcingRepository<PanelContext> eventSourcingRepository() {
EventSourcingRepository<PanelContext> repository = new EventSourcingRepository<>(PanelContext.class, eventStore());
repository.setEventBus(eventBus());
return repository;
}

// @Bean @Lazy(false)
// public AggregateAnnotationCommandHandler<PanelContext> commandHandler() {
// return AggregateAnnotationCommandHandler.subscribe(PanelContext.class, eventSourcingRepository(), commandBus());
// }
//
// @Bean @Lazy(false)
// public AnnotationEventListenerAdapter eventHandler() {
// return AnnotationEventListenerAdapter.subscribe(commandHandler, eventBus());
// }

`

My Aggregate :

`

public class PanelContext extends AbstractAnnotatedAggregateRoot {

@AggregateIdentifier
Integer id;
`…

public PanelContext(Integer id, Channel channelHandlerContext) {
apply(new PanelContextCreated(id, channelHandlerContext));

}

@EventSourcingHandler
public void on(PanelContextCreated panelContextCreated){
this.id = panelContextCreated.getId();
this.channel = panelContextCreated.getChannel();
this.panel = new Panel();
}
`

`

My Event and Command Handler (where the problem is, but the command handler is working fine)

@Component public class CommandHandler {`

// This command handler is working fine

@CommandHandler
public void on(NewInitFrameCommand newInitFrameCommand) throws IOException{
...
}

`// Never able to make it work ;-(

@EventHandler
public void handle(PanelContextCreated panelContextCreated) {

}
}

Any Idea at all , i need to make a presentation on Monday for my company to evaluate the prototype and i’m still unable to make it work ;-( what i’m missing, why i’m not getting any event into my singelton Event Handler … There is something i missed or a something,

Any help would be more than appreciated !!! thanks

Hi,

the only thing I can see rightnow that is different from all the other situations, is that you have an @ComandHandler and @EventHandler in the same bean. It should work, but maybe that causes an issue.

When I have a little more screen space than a phone, I will try to run you sample to figure out what happens. With a little luck I’ll be able to do that today.

One thing you could try to debug is check whether the handler is subscribed to the event bus. Put a breakpoint on the subscribe method and see what happens.
Alternatively, look for all the beans that implement ‘EventListener’. You should find your @EventHandler annotated bean there.

Cheers,

Allard

Hi,

I have tried to reconstruct your context, to reproduce the problem. I might have found the issue. Are you using CommandGateway.send(…) to send your command?
By default, the DefaultCommandGateway uses a NoOpCallback, which does (As the name suggests) absolutely nothing. You could either use sendAndWait() or pass in a callback as second parameter to send(). You’ll see that the callback gets invoked. In my case, I got an exception about an aggregate already existing. That obviously made sense, as my script had a hard-coded aggregate.

Using NoOpCallback as a default wasn’t probably a very good choice, but it won’t be fixed before you give your presentation on monday.

Cheers,

Allard

Hi Allard, thank you so much for spending quality time to resolve my problem. How can i thank you ?

I tried your suggestion fixed and it didn’t helped. Actually i found out the problem
I was calling my aggregate constructor without a CommandHandler in the constructor.

Well i have a CommandHandler bean which is trigged whenever a command of type NewInitFrameCommand is send, and inside that CommandHandler method i’m creating a aggreagate by using new PanelContext which in his turn apply a event, but that event is never caught by the NewFrameCommand bean because the event was never associated int the context of that command

Now i have added a command (PanelContextCreateCommand) and wrap that construct inside a CommandHandler annotation and now i’m seing that event published during the commit

so we have that

Bad version:

Bean -> send NewFrameCommand -> FrameCommandHandler -> call constructor PanelContext -> apply PanelContextCreatedEvent (Event Handler never caught it)

now good version :

Bean -> send NewFrameCommand -> FrameCommandHandler -> send PanelContextCreateCommand -> call constructor PanelContext -> apply PanelContextCreatedEvent (EventSourcehandler caught it but not other Event Handlers)

and i added this into PanelContext :

@CommandHandler public PanelContext(CreatePanelContextCommand createPanelContextCommand) { apply(new PanelContextCreated(createPanelContextCommand.getId(), createPanelContextCommand.getChannel())); }

So now i dont understand why in the first version the event is never added into the event to publish with in the context of the Unit of Work of NewFrameCommand

Why i need to wrap it into a different Command to have it consider to be publish

is that by design ?

Hi,

you don’t need to use a Command object in an aggregate constructor. However, did you do repository.add(aggregate) after invoking the constructor?
Probably, you now have a scenario where 2 command handlers listen for the same the command. Since the last one prevails, it’s possible that after a few deployments, suddenly the “wrong” command handler wins and breaks your application.

Cheers,

Allard