EventBus
is the mechanism that dispatches events to the subscribed event handlers. Axon provides three implementations of the Event Bus: AxonServerEventStore
, EmbeddedEventStore
and SimpleEventBus
. All three implementations support subscribing and tracking processors (see Events Processors). However, the AxonServerEventStore
and EmbeddedEventStore
persist events (see Event Store), which allows you to replay them at a later stage. The SimpleEventBus
has a volatile storage and 'forgets' events as soon as they have been published to subscribed components.AxonServerEventStore
event bus/store is configured by default.AxonServerEventStore
. It connects to the AxonIQ AxonServer Server to store and retrieve Events.axon-spring-boot-starter
, Axon will automatically configure the event bus/event store:Excluding the Axon Server ConnectorIf you exclude theaxon-server-connector
dependency fromaxon-spring-boot-starter
theEmbeddedEventStore
will be auto-configured for you, if a concrete implementation ofEventStorageEngine
is available. If JPA or JDBC is detected on the classpath, aJpaEventStorageEngine
orJdbcEventStorageEngine
will respectively be auto-configured as theEventStorageEngine
. In absence of either, the auto configuration falls back to theSimpleEventBus
.
EmbeddedEventStore
. It delegates the actual storage and retrieval of events to an EventStorageEngine
.EventStorageEngine
implementations available:JpaEventStorageEngine
JpaEventStorageEngine
stores events in a JPA-compatible data source. The JPA event store stores events in entries. These entries contain the serialized form of an event, as well as some fields where metadata is stored for fast lookup of these entries. To use the JpaEventStorageEngine
, you must have the JPA (javax.persistence
) annotations on your classpath.META-INF/persistence.xml
file) to contain the classes DomainEventEntry
and SnapshotEventEntry
(both of these classes are located in the org.axonframework.eventsourcing.eventstore.jpa
package).DomainEventEntry
(the class used by the JpaEventStore
) with the persistence context.Unique Key Constraint ConsiderationAxon uses locking to prevent two threads from accessing the same aggregate. However, if you have multiple JVMs using the same database, this won't help you. In that case, you'd have to rely on the database to detect conflicts. Concurrent access to the event store will result in a Key Constraint Violation, as the table only allows a single event for a given aggregate and sequence number. Therefore, inserting a second event for an existing aggregate with an existing sequence number will result in an error.TheJpaEventStorageEngine
can detect this error and translate it to aConcurrencyException
. However, each database system reports this violation differently. If you register yourDataSource
with theJpaEventStore
, it will try to detect the type of database and figure out which error codes represent a Key Constraint Violation. Alternatively, you may provide aPersistenceExceptionTranslator
instance, which can tell if a given exception represents a key constraint violation.If noDataSource
orPersistenceExceptionTranslator
is provided, exceptions from the database driver are thrown as-is.
JpaEventStorageEngine
requires an EntityManagerProvider
implementation that returns the EntityManager
instance for the EventStorageEngine
to use. This also allows application managed persistence contexts to be used. It is the EntityManagerProvider
's responsibility to provide a correct instance of the EntityManager
.EntityManagerProvider
available, each for different needs. The SimpleEntityManagerProvider
simply returns the EntityManager
instance which is given to it at construction time. This makes the implementation a simple option for container managed contexts. Alternatively, there is the ContainerManagedEntityManagerProvider
, which returns the default persistence context, and is used by default by the JPA event store."myPersistenceUnit"
which you wish to use in the JpaEventStore
, the EntityManagerProvider
implementation could look like this:DomainEventEntry
and SnapshotEventEntry
entities. While this will suffice in many cases, you might encounter a situation where the metadata provided by these entities is not enough. It is also possible that you might want to store events for different aggregate types in different tables.JpaEventStorageEngine
. It contains a number of protected methods that you can override to tweak its behavior.WarningNote that persistence providers, such as Hibernate, use a first-level cache in theirEntityManager
implementation. Typically, this means that all entities used or returned in queries are attached to theEntityManager
. They are only cleared when the surrounding transaction is committed or an explicit "clear" is performed inside the transaction. This is especially the case when the queries are executed in the context of a transaction.To work around this issue, make sure to exclusively query for non-entity objects. You can use JPA's"SELECT new SomeClass(parameters) FROM ..."
style queries to work around this issue. Alternatively, callEntityManager.flush()
andEntityManager.clear()
after fetching a batch of events. Failure to do so might result inOutOfMemoryException
s when loading large streams of events.
Excluding the Axon Server ConnectorIf you exclude theaxon-server-connector
dependency fromaxon-spring-boot-starter
theEmbeddedEventStore
will be auto-configured for you, if a concrete implementation ofEventStorageEngine
is available. If JPA or JDBC is detected on the classpath, aJpaEventStorageEngine
orJdbcEventStorageEngine
will respectively be auto-configured as theEventStorageEngine
. In absence of either, the auto configuration falls back to theSimpleEventBus
.
JdbcEventStorageEngine
.JDBCEventStorageEngine
stores events in entries. By default, each event is stored in a single entry, which corresponds with a row in a table. The storage engine uses one table for events and another for snapshots.JdbcEventStorageEngine
uses a ConnectionProvider
to obtain connections. Typically, the engine can obtain these connections directly from a DataSource
. However, Axon will bind these connections to a UnitOfWork
to use a single connection within a unit of work. This approach ensures that the framework uses a single transaction to store all events, even when multiple units of work are nested in the same thread.JdbcAutoConfiguration
will automatically generate the JdbcEventStorageEngine
for you. All that might be left is the creation of the schema. Axon can help you here with the createSchema
operation:Data sources providers with SpringWe recommend that Spring users use theSpringDataSourceConnectionProvider
to attach a connection from aDataSource
to an existing transaction.
SQL Statement CustomizabilityDatabases have slight deviations from what's the optimal SQL statement to perform in differing scenarios. Since optimizing for all possibilities out there is beyond the framework's scope, you can adjust the default statements used by the storage engine.Check theJdbcEventStorageEngineStatements
utility class for the default statements used by theJdbcEventStorageEngine
. Furthermore, theorg.axonframework.eventsourcing.eventstore.jdbc.statements
package contains the set of adjustable statements. Each of these statement-builders can be customized through theJdbcEventStorageEngine.Builder
.
MongoEventStorageEngine
, which uses MongoDB as a backing database. It is contained in the Axon Mongo module (Maven artifactId axon-mongo
).MongoEventStorageEngine
stores each event in a separate document. It is, however, possible to change the StorageStrategy
used. The alternative provided by Axon is the DocumentPerCommitStorageStrategy
, which creates a single document for all events that have been stored in a single commit (i.e. in the same DomainEventStream
).MongoEventStorageEngine
does not require a lot of configuration. All it needs is a reference to the collections to store the events in, and you're set to go. For production environments, you may want to double check the indexes on your collections.Excluding the Axon Server ConnectorIf you exclude theaxon-server-connector
dependency fromaxon-spring-boot-starter
theEmbeddedEventStore
will be auto-configured for you, if a concrete implementation ofEventStorageEngine
is available. When it is desired to use Mongo as the Event Storage approach, this means providing aMongoEventStorageEngine
bean.
InMemoryEventStorageEngine
keeps stored events in memory. While it probably outperforms any other event store out there, it is not really meant for long-term production use. However, it is very useful in short-lived tools or tests that require an event store.Excluding the Axon Server ConnectorIf you exclude theaxon-server-connector
dependency fromaxon-spring-boot-starter
theEmbeddedEventStore
will be auto-configured for you, if a concrete implementation ofEventStorageEngine
is available. When it is desired to use an in-memory Event Storage approach, this means providing anInMemoryEventStorageEngine
Bean.
SequenceEventStorageEngine
is a wrapper around two other event storage engines. When reading, it returns the events from both event storage engines. Appended events are only appended to the second event storage engine. This is useful in cases where two different implementations of event storage are used for performance reasons, for example. The first would be a larger, but slower event store, while the second is optimized for quick reading and writing.FilteringEventStorageEngine
allows events to be filtered based on a predicate. Only events that match the given predicate will be stored. Note that event processors that use the event store as a source of events may not receive these events because they are not being stored.XStreamSerializer
, which uses XStream to serialize events into XML. XStream is reasonably fast and is more flexible than Java Serialization. Furthermore, the result of XStream serialization is human readable. This makes it quite useful for logging and debugging purposes.XStreamSerializer
can be configured. You can define aliases it should use for certain packages, classes or even fields. Besides being a nice way to shorten potentially long names, aliases can also be used when class definitions of events change. For more information about aliases, visit the XStream website.JacksonSerializer
, which uses Jackson to serialize events into JSON. While it produces a more compact serialized form, it does require that classes stick to the conventions (or configuration) required by Jackson.Serializer
, and configuring the event store to use that implementation instead of the default.application.properties
:XStreamSerializer
's capability to serialize virtually anything makes it a very decent default, its output is not always a form that makes it nice to share with other applications. The JacksonSerializer
creates much nicer output, but requires a certain structure in the objects to serialize. This structure is typically present in events, making it a very suitable event serializer.eventSerializer
is configured, events are serialized using the main serializer that has been configured (which defaults to the XStreamSerializer
).EventStore
's data source between these applications. We may thus achieve distribution by utilizing the source itself. You can use both the EmbeddedEventStore
and Axon Server for this. The former would require the applications to point to the same data source, whereas the latter would require the applications to partake in the same context.AxonServerEventStore#createStreamableMessageSourceForContext(String)
operation. With this source in hand, you can configure a Streaming Processor to start reading from it.