Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/joel-jeremy/deezpatch
A simple fast dispatch library.
https://github.com/joel-jeremy/deezpatch
dispatcher event eventbus java jvm messaging publisher requests
Last synced: about 2 months ago
JSON representation
A simple fast dispatch library.
- Host: GitHub
- URL: https://github.com/joel-jeremy/deezpatch
- Owner: joel-jeremy
- License: apache-2.0
- Created: 2022-09-05T06:53:05.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2024-04-29T02:10:51.000Z (about 2 months ago)
- Last Synced: 2024-04-29T03:25:13.743Z (about 2 months ago)
- Topics: dispatcher, event, eventbus, java, jvm, messaging, publisher, requests
- Language: Java
- Homepage:
- Size: 429 KB
- Stars: 39
- Watchers: 2
- Forks: 2
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Lists
- awesome-java - Deezpatch - Simple, lightweight, and performant dispatch library for decoupling messages (requests and events) and message handlers. (Projects / Messaging)
- awesome-java-zh - Deezpatch - 用于解耦消息 (请求和事件) 和消息处理程序的简单,轻量级和高性能的调度库。 (项目 / 消息传递)
README
# Deezpatch
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://github.com/joel-jeremy/deezpatch/blob/main/LICENSE)
[![Gradle Build](https://github.com/joel-jeremy/deezpatch/actions/workflows/gradle-build.yaml/badge.svg)](https://github.com/joel-jeremy/deezpatch/actions/workflows/gradle-build.yaml)
[![Code QL](https://github.com/joel-jeremy/deezpatch/actions/workflows/codeql.yaml/badge.svg)](https://github.com/joel-jeremy/deezpatch/actions/workflows/codeql.yaml)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.joel-jeremy.deezpatch/core/badge.svg)](https://search.maven.org/search?q=g:%22io.github.joel-jeremy.deezpatch%22)
[![Coverage Status](https://coveralls.io/repos/github/joel-jeremy/deezpatch/badge.svg?branch=main)](https://coveralls.io/github/joel-jeremy/deezpatch?branch=main)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=io.github.joel-jeremy.deezpatch&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=io.github.joel-jeremy.deezpatch)
[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=io.github.joel-jeremy.deezpatch&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=io.github.joel-jeremy.deezpatch)
[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=io.github.joel-jeremy.deezpatch&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=io.github.joel-jeremy.deezpatch)
[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=io.github.joel-jeremy.deezpatch&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=io.github.joel-jeremy.deezpatch)
[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=io.github.joel-jeremy.deezpatch&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=io.github.joel-jeremy.deezpatch)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=io.github.joel-jeremy.deezpatch&metric=coverage)](https://sonarcloud.io/summary/new_code?id=io.github.joel-jeremy.deezpatch)
[![Discord](https://img.shields.io/discord/1025648239162175578.svg?logo=discord&logoColor=white&logoWidth=20&labelColor=7289DA&label=Discord&color=17cf48)](https://discord.gg/bAfgXRVx3T)A simple fast dispatch library.
The library aims to help build applications which apply the [Command Query Responsibility Segregation](https://martinfowler.com/bliki/CQRS.html) (CQRS) pattern.
## Like the project?
Please consider giving the repository a ⭐. It means a lot! Thank you :)
## 🛠️ Get Deezpatch
### Gradle
```groovy
implementation "io.github.joel-jeremy.deezpatch:deezpatch-core:${version}"
```### Maven
```xml
io.github.joel-jeremy.deezpatch
deezpatch-core
${version}```
### 🧩 Java 9 Module Names
Deezpatch jars are published with Automatic-Module-Name manifest attribute:
- Core - `io.github.joeljeremy.deezpatch.core`
Module authors can use above module names in their module-info.java:
```java
module foo.bar {
requires io.github.joeljeremy.deezpatch.core;
}
```## 🚀 Performance
What differentiates Deezpatch from other messaging/dispatch libraries? The library takes advantage of the benefits provided by [java.lang.invoke.LambdaMetafactory](https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/LambdaMetafactory.html) to avoid the cost of invoking methods reflectively. This results in performance close to directly invoking the request handler and event handler methods!
### [Java 11 Benchmarks](https://jmh.morethan.io/?source=https://raw.githubusercontent.com/joel-jeremy/deezpatch/main/deezpatch-core/src/jmh/java/io/github/joeljeremy/deezpatch/core/benchmarks/results-java11.json)
### [Java 17 Benchmarks](https://jmh.morethan.io/?source=https://raw.githubusercontent.com/joel-jeremy/deezpatch/main/deezpatch-core/src/jmh/java/io/github/joeljeremy/deezpatch/core/benchmarks/results-java17.json)
## ✉️ Requests
Requests are messages that either:
1. Initiate a state change/mutation
- Commands in [CQRS](https://martinfowler.com/bliki/CQRS.html)
2. Retrieve/query data
- Queries in [CQRS](https://martinfowler.com/bliki/CQRS.html)```java
public class GreetCommand implements Request {
private final String name;
public GreetRequest(String name) {
this.name = name;
}
public String name() {
return name;
}
}public class PingQuery implements Request {}
```## 📨 Request Handlers
Requests are handled by request handlers. Request handlers can be registered through the use of the [@RequestHandler](deezpatch-core/src/main/java/io/github/joeljeremy/deezpatch/core/RequestHandler.java) annotation.
A request must only have a single request handler.
**(`@RequestHandler`s fully support methods with `void` return types! No need to set method return type to `Void` and return `null` for no reason.)**
```java
public class GreetCommandHandler {
@RequestHandler
public void handle(GreetCommand command) {
sayHi(command.name());
}
}public class PingQueryHandler {
@RequestHandler
public Pong handle(PingQuery query) {
return new Pong("Here's your pong!");
}
}
```## 🏤 Request Dispatcher
Requests are dispatched to a single request handler and this can be done through a dispatcher.
```java
public static void main(String[] args) {
// Use Spring's application context as InstanceProvider in this example
// but any other DI framework can be used e.g. Guice, Dagger, etc.
ApplicationContext applicationContext = springApplicationContext();// Deezpatch implements the Dispatcher interface.
Dispatcher dispatcher = Deezpatch.builder()
.instanceProvider(applicationContext::getBean)
.requests(config -> config.handlers(
GreetCommandHandler.java,
PingQueryHandler.java
))
.build();// Send command!
dispatcher.send(new GreetCommand("Deez"));// Send query!
Optional pong = dispatcher.send(new PingQuery());
}
```## ✉️ Events
Events are messages that indicate that something has occurred in the system.
```java
public class GreetedEvent implements Event {
private final String greeting;public GreetedEvent(String greeting) {
this.greeting = greeting;
}public String greeting() {
return greeting;
}
}
```## 📨 Event Handlers
Events are handled by event handlers. Event handlers can be registered through the use of the [@EventHandler](deezpatch-core/src/main/java/io/github/joeljeremy/deezpatch/core/EventHandler.java) annotation.
An event can have zero or more event handlers.
```java
public class GreetedEventHandler {
@EventHandler
public void sayHello(GreetedEvent event) {
// Well, hello!
}@EventHandler
public void sayKumusta(GreetedEvent event) {
// Well, kumusta?
}@EventHandler
public void sayGotEm(GreetedEvent event) {
// Got 'em!
}
}
```## 📣 Event Publisher
Events are dispatched to zero or more event handlers and this can be done through a publisher.
```java
public static void main(String[] args) {
// Use Spring's application context as InstanceProvider in this example
// but any other DI framework can be used e.g. Guice, Dagger, etc.
ApplicationContext applicationContext = springApplicationContext();// Deezpatch implements the Publisher interface.
Publisher publisher = Deezpatch.builder()
.instanceProvider(applicationContext::getBean)
.events(config -> config.handlers(
GreetedEventHandler.java
))
.build();// Publish event!
publisher.publish(new GreetedEvent("Hi from Deez!"));
}
```## 🔩 Easy Integration with Dependency Injection (DI) Frameworks
The library provides an [InstanceProvider](deezpatch-core/src/main/java/io/github/joeljeremy/deezpatch/core/InstanceProvider.java) interface as an extension point to let users customize how request/event handler instances should be instantiated. This can be as simple as `new`-ing up request/event handlers or getting instances from a DI framework such as Spring's `ApplicationContext`, Guice's `Injector`, etc.
### Example with No DI framework
```java
// Application.javapublic static void main(String[] args) {
Deezpatch deezpatch = Deezpatch.builder()
.instanceProvider(Application::getInstance)
.requests(...)
.events(...)
.build();
}private static Object getInstance(Class> handlerType) {
if (MyRequestHandler.class.equals(handlerType)) {
return new MyRequestHandler();
} else if (MyEventHandler.class.equals(handlerType)) {
return new MyEventHandler();
}throw new IllegalStateException("Failed to get instance for " + handlerType.getName() + ".");
}
```### Example with Spring's ApplicationContext
```java
public static void main(String[] args) {
ApplicationContext applicationContext = springApplicationContext();
Deezpatch deezpatch = Deezpatch.builder()
.instanceProvider(applicationContext::getBean)
.requests(...)
.events(...)
.build();
}
```### Example with Guice's Injector
```java
public static void main(String[] args) {
Injector injector = guiceInjector();
Deezpatch deezpatch = Deezpatch.builder()
.instanceProvider(injector::getInstance)
.requests(...)
.events(...)
.build();
}
```## 🎛️ Custom Request/Event Handler Annotations
In cases where a project is built in such a way that bringing in external dependencies is considered a bad practice (e.g. domain layer/package in a Hexagonal (Ports and Adapters) architecture), Deezpatch provides a way to use custom request/event handler annotations (in addition to the built-in [RequestHandler](deezpatch-core/src/main/java/io/github/joeljeremy/deezpatch/core/RequestHandler.java) and [EventHandler](deezpatch-core/src/main/java/io/github/joeljeremy/deezpatch/core/EventHandler.java) annotations) to annotate request/event handlers.
This way, Deezpatch can still be used without adding the core Deezpatch library as a dependency of a project's domain layer/package. Instead, it may be used in the outer layers/packages to wire things up.
```java
// Let's say below classes are declared in a project's core/domain package:@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AwesomeRequestHandler {}@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AwesomeEventHandler {}public class MyRequestHandler {
@AwesomeRequestHandler
public void handle(TestRequest request) {
// Handle.
}
}public class MyEventHandler {
@AwesomeEventHandler
public void handle(TestEvent event) {
// Handle.
}
}// To wire things up:
public static void main(String[] args) {
// Use Spring's application context as InstanceProvider in this example
// but any other DI framework can be used e.g. Guice, Dagger, etc.
ApplicationContext applicationContext = springApplicationContext();// Register handlers and custom annotations.
Deezpatch deezpatch = Deezpatch.builder()
.instanceProvider(applicationContext::getBean)
.requests(config ->
config.handlerAnnotations(AwesomeRequestHandler.class)
.handlers(MyRequestHandler.class))
.events(config ->
config.handlerAnnotations(AwesomeEventHandler.java)
.handlers(MyEventHandler.class))
.build();
}
```