@Aggregate
annotation (in the org.axonframework.spring.stereotype
package) triggers auto configuration to set up the necessary components to use the annotated type as an aggregate. Note that only the aggregate root needs to be annotated.@CommandHandler
annotated methods with the command bus and set up a repository if none is present.GiftCardCommandHandler
as being a Command Handler:Duplicate Command Handling FunctionsAs specified in the Messaging Concepts section, a command always has exactly one destination. That means there should only be a single Command Handler method for any given command.By default, when a duplicate Command Handler method is registered, the last registration will be kept and a warning is logged. This behaviour can be adjusted by specifying a differentDuplicateCommandHandlerResolver
, as is described in the Runtime Tuning section.
Repository
interface. This interface prescribes three methods: load(identifier, version)
, load(identifier)
and newInstance(factoryMethod)
. The load
methods allows you to load aggregates from the repository. The optional version
parameter is used to detect concurrent modifications (see Conflict resolution). newInstance
is used to register newly created aggregates in the repository.delete(identifier)
method. Deleting aggregates is done by invoking the AggregateLifecycle.markDeleted()
method from within an aggregate. Deleting an aggregate is a state migration like any other, with the only difference that it is irreversible in many cases. You should create your own meaningful method on your aggregate which sets the aggregate's state to "deleted". This also allows you to register any events that you would like to have published.repository
attribute on @Aggregate
Annotation. Alternatively, specify the bean name of the repository to be the aggregate's name, (first character lowercase), suffixed with Repository
. So on a class of type GiftCard
, the default repository name is giftCardRepository
. If no bean with that name is found, Axon will define an EventSourcingRepository
(which fails if no EventStore
is available).SnapshotTriggerDefinition
or AggregateFactory
that may otherwise have been configured automatically.GenericJpaRepository
. It expects the Aggregate to be a valid JPA Entity. It is configured with an EntityManagerProvider
which provides the EntityManager
to manage the actual persistence, and a class specifying the actual type of aggregate stored in the repository. You also pass in the EventBus
to which events are to be published when the aggregate invokes the static AggregateLifecycle.apply()
method.LockingRepository
. As aggregate wrapper type, it is recommended to use the AnnotatedAggregate
. See the sources of GenericJpaRepository
for an example.EventSourcingRepository
implementation provides the basic functionality needed by any event sourcing repository in the Axon Framework. It depends on an EventStore
(see Event store implementations), which abstracts the actual storage mechanism for the events.AggregateFactory
specifies how an aggregate instance is created. Once an aggregate has been created, the EventSourcingRepository
can initialize it using the events it loaded from the event store. Axon Framework comes with a number of AggregateFactory
implementations that you may use. If they do not suffice, it is very easy to create your own implementation.GenericAggregateFactory
is a special AggregateFactory
implementation that can be used for any type of event sourced aggregate root. The GenericAggregateFactory
creates an instance of the aggregate type the repository manages. The aggregate class must be non-abstract and declare a default no-arg constructor that does no initialization at all.GenericAggregateFactory
is suitable for most scenarios where aggregates do not need special injection of non-serializable resources.SpringPrototypeAggregateFactory
. Instead of creating regular instances of using a constructor, it uses the Spring Application Context to instantiate your aggregates. This will also inject any dependencies in your aggregate.GenericAggregateFactory
just doesn't deliver what you need. For example, you could have an abstract aggregate type with multiple implementations for different scenarios (e.g. PublicUserAccount
and BackOfficeAccount
both extending an Account
). Instead of creating different repositories for each of the aggregates, you could use a single repository, and configure an AggregateFactory that is aware of the different implementations.CachingEventSourcingRepository
provides a cache from which aggregates can be loaded if available.