Table of contents
Overview
Simple command handling library!
This project composes of components for implementing the command handling parts of the CQRS pattern. This library was built with simplicity, modularity and pluggability in mind.
Features
- Send commands to registered command handlers.
- Multiple ways of registering command handlers:
-
Simple registration (no IoC container).
-
IoC container registration
- achieved by creating implementations of CommandHandlerProvider: See sample CommandHandlerProvider implementations
-
Attribute registration (Soon!)
- achieved by marking methods with @CommandHandler annotations.
-
Installation
-
XerJ.CommandStack is also available in the Maven Central:
Maven:
<dependency> <groupId>io.github.xerprojects</groupId> <artifactId>xerj.commandstack</artifactId> <version>${xerj.commandstack.version}</version> </dependency>
Gradle:
implementation group: 'io.github.xerprojects', name: 'xerj.commandstack', version: $rootProject.commandStackVersion
Getting Started
Sample Command and Command Handler
Commands are just POJOs or if you are in a later java version, you can use records if you prefer.
// Example POJO command.
public class RegisterProductCommand {
private final int productId;
private final String productName;
public RegisterProductCommand(int productId, String productName) {
this.productId = productId;
this.productName = productName;
}
public int getProductId() {
return productId;
}
public String getProductName() {
return productName;
}
}
// Command handler.
public class RegisterProductCommandHandler implements CommandHandler<RegisterProductCommand> {
private final ProductRepository productRepository;
public RegisterProductCommandHandler(ProductRepository productRepository) {
this.productRepository = productRepository;
}
@Override
public void handle(RegisterProductCommand command) {
validate(command);
productRepository.save(new Product(command.getProductId(), command.getProductName()));
}
}
Command Handler Registration
Before we can dispatch any commands, first we need to register our command handlers. There are several ways to do this:
1. Built-in (No dependency injection frameworks)
public static void main(String[] args) {
RegistryCommandHandlerProvider provider = new RegistryCommandHandlerProvider(registry -> {
registry.registerCommandHandler(RegisterProductCommand.class, () ->
new RegisterProductCommandHandler(
new InMemoryProductRepository()
)
);
});
CommandDispatcher dispatcher = new CommandStackDispatcher(provider);
// Dispatch command.
dispatcher.send(new RegisterProductCommand(1, "My Product Name"));
}
2. Dependency Injection Frameworks
-
Spring Context - See Sample Spring Context Command Handler Provider
-
Guice - See Sample Guice Command Handler Provider
-
Dagger - See Sample Dagger Command Handler Provider
Async Dispatch
Async dispatch is supported by decorating the CommandStackDispatcher
with AsyncCommandDispatcher
:
public static void main(String[] args) {
ExecutorService executor = Executors.newWorkStealingPool();
CommandHandlerProvider commandHandlerProvider = getCommandHandlerProvider();
CommandDispatcher dispatcher = new AsyncCommandDispatcher(
new CommandStackDispatcher(commandHandlerProvider),
executor);
dispatcher.send(new RegisterProductCommand(1, "My Product Name"));
}