Inject Spring Beans into Aggregate how to configure?

Hi
I tried to inject Spring beans into an aggregate, but failed miserably.
I guess my configuration is not correct.
If I may show you what I did, maybe someone could give me some advices.

I reduced the application to the minimum.
It is a Spring-boot application
Here is my Main class

`
@Configuration
@EnableAutoConfiguration
@ComponentScan
@Component
class Application {
@Autowired
private MyBean myBean;
@Autowired
private CommandGateway commandGateway;

public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
Application app = context.getBean(Application.class);
app.greet();
System.exit(0);
}

private void greet() {
System.out.println("Greet: + " + myBean.getMe());
commandGateway.send(new CreateCommand());
}
}
`

The my Axon config:

`
@Configuration
class AxonConfig {

@Bean
AnnotationEventListenerBeanPostProcessor annotationEventListenerBeanPostProcessor() {
return new AnnotationEventListenerBeanPostProcessor();
}

@Bean
AnnotationCommandHandlerBeanPostProcessor annotationCommandHandlerBeanPostProcessor() {
return new AnnotationCommandHandlerBeanPostProcessor();
}

@Bean
CommandBus commandBus() {
return new SimpleCommandBus();
}

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

@Bean
public CommandGatewayFactoryBean commandGatewayFactoryBean() {
CommandGatewayFactoryBean factory = new CommandGatewayFactoryBean<>();
factory.setCommandBus(commandBus());
return factory;
}

@Bean
public EventSourcingRepository eventSourcingRepository() {
FileSystemEventStore eventStore = new FileSystemEventStore(new SimpleEventFileResolver(new File(“eventstore”)));
EventSourcingRepository repository = new EventSourcingRepository<>(MyAgg.class, eventStore);
repository.setEventBus(eventBus());
return repository;
}

@Bean
public AggregateAnnotationCommandHandler commandHandler() {
return AggregateAnnotationCommandHandler.subscribe(MyAgg.class, eventSourcingRepository(), commandBus());
}
}
`

finally my Aggregate

`
public class MyAgg extends AbstractAnnotatedAggregateRoot {

@AggregateIdentifier
private long id;

MyAgg() {
}

@CommandHandler
public MyAgg(CreateCommand command) throws IOException {
apply(new CreateEvent(new Random().nextInt()));
System.out.println(“command ok”);
}

@EventHandler
public void id(CreateEvent event, MyBean myBean ) throws IOException {
id = event.getId();
System.out.println("event greets " + myBean.getMe() );
}
}

`

I omit the Command and the event as they are trivial.
In the CommandHandler as well as in the EventHandler methods of the Aggregate the SpringBean MyBean lead to an exception:

org.axonframework.common.annotation.UnsupportedHandlerException: On method public void org.axon.sample.inject.bean.MyAgg.id(org.axon.sample.inject.bean.CreateEvent,org.axon.sample.inject.bean.MyBean) throws java.io.IOException, parameter 2 is invalid. It is not of any format supported by a providedParameterValueResolver.

According to the documentation it should be possible to inject beans into an aggregate.

6.2.2
When using Spring and <axon:annotation-config/> is declared, any other parameters will resolve to autowired beans, if exactly one injectable candidate is available in the application context. This allows you to inject resources directly into @EventHandler annotated methods. Note that this only works for Spring-managed beans. Event Sourcing handlers on Aggregate instances don’t get resources injected.

I must confess I’m not sure about the last sentence. “Event Sourcing handlers on Aggregate instances don’t get resources injected.”
Do I have this? If so I don’t need event sourcing, It is just my first implementation that I want to elaborate on.

Thanks for your help.

Hi Frank,

I just discussed a similar question two minutes ago ;-). The messages probably met eachother halfway.
You’ll need to use the AggregateAnnotationCommandHandlerFactoryBean if you want to use java config. With xml, this is a little easier: <axon:aggreate-command-handler …/>.
This is still one of the things I want to make a bit easier, nut just didn’t get to it yet.

Cheers,

Allard

Hi Frank,

alternatively, you can also use the AggregateAnnotationCommandHandler constructor that allows you to configure a ParameterResolverFactory. The instance thereof that you’ll want is a MultiParameterResolverFactory with both a ClasspathParameterResolverFactory and a SpringBeanParameterResolverFactory. The last one has to be defined as a separate spring bean, so that Spring can do the proper wiring.

It’s all quite complex, but the xml definition does this all automatically.
Cheers,

Allard

If I get you correctly, you would recommend to use xml config until you made it easier to configure with Javaconfig?

I will try to do this :slight_smile:

Thanks a lot.

I also has some problems with this (if I’m understanding correctly) and in the end I came up with this configuration that it allows me to inject beans in the aggregate the normal way.

The Aggregate:

`
public class AuditServiceAggregate extends AbstractAnnotatedAggregateRoot {
@AggregateIdentifier
private String id;
@Inject
private transient ServerInterface serverInterface; —> my own bean
@Inject
private transient CommandGateway commandGateway; —> Axon
(…)

`

The conf file:

`
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public AuditServiceAggregate auditServiceAggregate() {
AuditServiceAggregate auditServiceAggregate = new AuditServiceAggregate();
return auditServiceAggregate;
}

@Bean
public SpringPrototypeAggregateFactory aggregateFactory() {
SpringPrototypeAggregateFactory aggregateFactory = new SpringPrototypeAggregateFactory();
aggregateFactory.setPrototypeBeanName(“auditServiceAggregate”);
return aggregateFactory;
}

`

Hope this help.

I tried to configure the same with xml.
I think I got the same config as with the java config.
Alas with the same error.

Here is my xml config

`

<?xml version="1.0" encoding="UTF-8"?>


<axon:annotation-config />
<axon:command-bus id=“commandBus”/>
<axon:event-bus id=“eventBus”/>
<axon:aggregate-command-handler aggregate-type=“org.axon.sample.inject.bean.MyAgg”
repository=“myRepository”
command-bus=“commandBus”/>
<axon:filesystem-event-store id=“eventStore” base-dir=“eventstore”/>
<axon:event-sourcing-repository id=“myRepository”
aggregate-type=“org.axon.sample.inject.bean.MyAgg”
event-bus=“eventBus” event-store=“eventStore”/>

`

I also tried the solution of Antonio, but the beans were not initialized :frowning:
I will have to look at AggregateAnnotationCommandHandlerFactoryBean. Maybe It will solve my problem

What is the error you get? Do you get an exception when starting up? Or is it just the bean not being injected?

Are you absolutely sure there is only one candidate for injection? If there is more than one, you can see so in the log files.

Note that the last bean in your xml config is not necessary. The axon:annotation-config element will take care of that.

Cheers,

Allard

What command bus are you using? It works with me using the SimpleCommandBus, that actually uses the AggregateAnnotationCommandHandlerFactoryBean that in turn uses the SpringPrototypeAggregateFactory that wires the beans using the Spring ApplicationContext. I tested today with the DispruptorCommandBus to find out that it does not use AggregateAnnotationCommandHandlerFactoryBean to actually create the aggregates, and thus does not wired them. I found that the hard way…

Allard, maybe that is something to review? Should be easy enough to implement.

The command bus implementation doesn’t really have an effect on the parameters being injected. The AggregateAnnotationCommandHandler is a CommandHandler implementation that forwards incoming command messages to an aggregate that it loads from repository.

If you had problems with the disruptor command bus, that might have something to do with the repository that you used. Did you configure the repositories inside the disruptor command bus bean, and then have the aggregate command handler refer to that repository instance? The disruptor command bus doesn’t support the normal EventSourcingRepository.

Cheers,

Allard

Yes I did, after I got some AggregationNotFound exceptions. Note that I’m talking not about the parameter injection but the @Injected beans.

And the problem is not with the AggregateAnnotationCommandHandler but with the AggregateAnnotationCommandHandlerFactoryBean, AFAICS the SImpleCommandBus uses it to actually instantiate the Aggregate and wire the instance using the SpringPrototypeAggregateFactory.

The DisruptorCommandBus does not uses it to instantiate, but only to introspect the command annotations. At least that what it looked to me. I can be more specific tomorrow with the code in front of me.

Cheers.

Ah, I see. It’s the AggregateFactory. I can’t recall how you can configure that. If it’s not available in the namespace, it should be relatively easy to implement.
I’ll check that once I have a proper device in front of me.

Cheers,

Allard

I’ve checked. It’s possible to use a custom aggregate factory in combination with the DisruptorCommandBus:

<axon:disruptor-command-bus id=“commandBus” event-bus=“eventBus” event-store=“eventStore”>
axon:repositories
<axon:repository id=“toDoRepository” aggregate-factory=“myCustomAggregateFactory”/>
</axon:repositories>
</axon:disruptor-command-bus>

Note that there is a difference between AggregeateAnnotationCommandHandler(FactoryBean) and AggregateFactory. The first provides the mechanism for invoking an aggregate based on its @CommandHandler annotations. The latter is the mechanism that creates ‘empty’ aggregate instances for the repository to stream historic events to. This is where you’ll need to use the SpringPrototypeAggregateFactory if you want to inject beans into an aggregate instance.

To inject beans as parameters of @CommandHandler methods, you’ll need the AggregateAnnotationCommandHandler(FactoryBean), with a ParameterResolverFactory that knows how to map parameters to Spring beans. If you use <axon:aggregate-command-handler aggregate-type=“org.axonframework.quickstart.annotated.ToDoItem” … />, this is configured automatically.

Cheers,

Allard