@CommandHandler
constructor(cmd: CreateMySecondAggregateCommand, myFirstAggregateRepository: Repository){
try {
myFirstAggregateRepository.load(cmd.mySecondAggregateId)
// do create the second aggregate
AggregateLifeCycle.apply(MySecondAggregateCreatedEvent(cmd.mySecondAggregateId))
} catch(e: AggregateNotFoundException) {
// reject the command
}
}
}
`
Axon Version: 4.2.1
Assume I’m using all default configurations from axon-spring-boot-starter.
Given this scenario I am unable to init the application because axon fails to inject myFirstAggregateRepository into the second aggregate command handler.
Maybe using @AutoWired as an instance variable would work?
To be honest I’ve never considered doing that, loading aggregates from other aggregates feels...impure. However the framework has cross-aggregate createNew functionality, so reading isn’t so far fetched. I’ll have to give this a try!
According to documentation the second expected parameter of a CommandHandler should be a UnitOfWork (see package org.axonframework.messaging.unitofwork for candidate implementations).
Looks like you got a piece of documentation from EventHandler which yes can autowire a Component if it is available in the Spring Context.
In your case following the @Joel’s advise and autowire the Repository in your aggregate seems to be the way to go.
I tried to get this working in command and event handlers w/ autowiring and parameter injecting. Nothing worked. Can’t say I’m surprised as this probably violates some tenant of DDD.
please note that parameter injection for Axon isn’t a full-fledged dependency injection mechanism. The Spring-bean injection will only work when there is a single bean of the expected type available. Because of generics type erasure, the type of the repository parameter is Repository. There are most likely multiple Spring beans that implement that interface (one for each aggregate).
But in this case, I’d argue that directly calling an aggregate from another is a design smell. Aggregates should execute their logic independent of eachother. Wherever they have a dependency, this is implemented using a Saga, Process Manager or “just-an-eventhandler-sending-commands”.
I can’t really make up your use case from the example, but it seems you want to create an aggregate from another. That’s a common use case, and is supported by Axon’s API directly. On the aggregate that already exists, call AggregateLifecycle.createNew(MySecondAggregate.class, () -> new MySecondAggregate(constructor, params));