-
Notifications
You must be signed in to change notification settings - Fork 5
Example of Spring Boot Config
Suppose all of your beans are placed in:
@Configuration
@EnableAutoConfiguration
public class Config {
First of all, we need to declare a JEventStore
bean - its the central component of the framework:
@Bean
public JEventStore eventStore(StoreProvider storeProvider) {
return new JEventStore(storeProvider);
}
JEventStore accepts a StoreProvider as an underlying component that handles all specific communication:
@Bean(destroyMethod = "close")
public StoreProvider storeProvider(DataSource dataSource, SerializationOption[] options) {
return new JdbcStoreProvider<>(dataSource, options);
}
// or
@Bean(destroyMethod = "close")
public StoreProvider storeProvider(EntityManagerFactory entityManagerFactory, SerializationOption[] options) {
return new JpaStoreProvider<>(entityManagerFactory, options);
}
// or
public StoreProvider storeProvider() {
return new InMemoryStoreProvider();
}
SerializationOptions is an optional parameter, it allows, for example, use event types aliasing when written in the event store:
// You can use any aliases for events. So you don't need to hardcode serialized class name of the event.
// Every client can create its model to deserialize events from the event store just using aliasing.
@Bean
public SerializationOption[] serializationOptions() {
final TypeRegistry registry = new TypeRegistry();
registry.addAlias(ItemCreated.class, ItemCreated.class.getSimpleName());
registry.addAlias(ItemRemoved.class, "ItemRemoved");
registry.addAlias(OrderPlaced.class, "Any other name I want");
return new SerializationOption[]{registry, Format.JSON_JACKSON};
}
If you plan to make some validation against aggregate state you need an AggregateStore
component:
@Bean
public AggregateStore aggregateStore(JEventStore eventStore) {
return new AggregateStore(eventStore);
}
// or
@Bean
public AggregateStore aggregateStore(JEventStore eventStore, SnapshotProvider snapshotProvider) {
return new AggregateStore(eventStore, snapshotProvider);
}
// or
@Bean
public AggregateStore aggregateStore(JEventStore eventStore, SnapshotProvider snapshotProvider,
SnapshotStrategy snapshotStrategy) {
return new AggregateStore(eventStore, snapshotProvider, snapshotStrategy);
}
Additional SnapshotProvider
and SnapshotStrategy
components are responsible for 'how' to make snapshots and 'when' to make it:
@Bean
public SnapshotProvider snapshotProvider() {
return new InMemorySnapshotProvider(CACHE_SIZE);
}
// or
@Bean
public SnapshotProvider snapshotProvider(DataSource dataSource) {
return new JdbcSnapshotProvider<>(dataSource);
}
// or
@Bean
public SnapshotProvider snapshotProvider(RedissonClient client) {
return new RedisSnapshotProvider(client);
}
and
@Bean
public SnapshotStrategy snapshotStrategy() {
return new SizeBasedSnapshotStrategy(SNAPSHOT_AFTER_SIZE);
}
// or
@Bean
public SnapshotStrategy snapshotStrategy() {
return new TimeBasedSnapshotStrategy(Duration.ofMillis(SNAPHOT_AFTER_DURATION));
}
// or just
@Bean
public SnapshotStrategy snapshotStrategy() {
return new AlwaysSnapshotStrategy();
}
To handle commands we need a command handler component. It accepts commands via command bus:
@Bean
public CommandBus commandBus() {
return new SyncCommandBus();
}
After that, you can create a component as usual:
@Component
public class StockHandler extends CommandHandler {
@Autowire
public StockHandler(@Nonnull JEventStore store, @Nonnull CommandBus bus) {
super(store, bus);
}
// or
@Autowire
public StockHandler(@Nonnull AggregateStore aggregateStore, @Nonnull CommandBus bus) {
super(aggregateStore, bus);
}
There another 2 top-level components left:
- Projector - make custom data view the easy way
- Saga - call appropriate action on event store changes
They require 2 additional beans to be declared in config:
@Bean
public Offset offset() {
return new InMemoryOffset();
}
// or
@Bean
public Offset offset(DataSource dataSource) {
return new JdbcOffset(dataSource);
}
// or
@Bean
public Offset offset(RedissonClient client) {
return new RedisOffset(client);
}
and
@Bean
public Lock lock() {
return new InMemoryReentrantLock();
}
// or
@Bean
public Lock lock(DataSource dataSource) {
return new JdbcLock(dataSource);
}
// or
@Bean
public Lock lock(RedissonClient client) {
return new RedisReentrantLock(client);
}
That's all. Now you can declare components as follows:
@Service
public class StockProjector extends Projector {
@Autowire
public StockProjector(@Nonnull JEventStore store, @Nonnull Offset offset, @Nonnull Lock lock) {
super(store, offset, lock);
}
@Service
public class StockSaga extends Saga {
@Autowire // stateless version
public OrderSaga(@Nonnull JEventStore store, @Nonnull Offset offset, @Nonnull Lock lock) {
super(store, offset, lock);
}
//or
@Autowire // stateful version
public OrderSaga(@Nonnull AggregateStore aggregateStore, @Nonnull Offset offset, @Nonnull Lock lock) {
super(aggregateStore, offset, lock);
}
That's all.