Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A simple yet 🗲FAST🗲 library to dispatch requests and events to corresponding handlers 🚀

License

NotificationsYou must be signed in to change notification settings

joel-jeremy/deezpatch

Repository files navigation

LicenseGradle BuildCode QLMaven CentralCoverage StatusQuality Gate StatusMaintainability RatingReliability RatingSecurity RatingVulnerabilitiesCoverageDiscord

A simple yet 🗲FAST🗲 library to dispatch requests and events to corresponding handlers 🚀

The library aims to take advantage of the intuitiveness of using the annotations for handlers (e.g.@RequestHandler/@EventHandler) without the drawbacks of reflection.

The library aims to help build applications which apply theCommand Query Responsibility Segregation (CQRS) pattern.

Like the project?

Please consider giving the repository a ⭐. It means a lot! Thank you :)

🛠️ Get Deezpatch

Gradle

implementation"io.github.joel-jeremy.deezpatch:deezpatch-core:${version}"

Maven

<dependency>    <groupId>io.github.joel-jeremy.deezpatch</groupId>    <artifactId>deezpatch-core</artifactId>    <version>${version}</version></dependency>

🧩 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:

modulefoo.bar {requiresio.github.joeljeremy.deezpatch.core;}

🚀 Performance

What differentiates Deezpatch from other messaging/dispatch libraries? The library takes advantage of the benefits provided byjava.lang.invoke.LambdaMetafactory to avoid the cost of invoking methods reflectively. This results in performance close to directly invoking the request handler and event handler methods!

~ 1000% more throughput compared to other similar libraries (Spring Events, Pipelinr, etc)

~ 90% less time compared to other similar libraries (Spring Events, Pipelinr, etc)

✉️ Requests

Requests are messages that either:

  1. Initiate a state change/mutation
  2. Retrieve/query data
publicclassGreetCommandimplementsRequest<Void> {privatefinalStringname;publicGreetRequest(Stringname) {this.name =name;    }publicStringname() {returnname;    }}publicclassPingQueryimplementsRequest<Pong> {}

📨 Request Handlers

Requests are handled by request handlers. Request handlers can be registered through the use of the@RequestHandler annotation.

A request must only have a single request handler.

(@RequestHandlers fully support methods withvoid return types! No need to set method return type toVoid and returnnull for no reason.)

publicclassGreetCommandHandler {@RequestHandlerpublicvoidhandle(GreetCommandcommand) {sayHi(command.name());    }}publicclassPingQueryHandler {@RequestHandlerpublicPonghandle(PingQueryquery) {returnnewPong("Here's your pong!");    }}

🏤 Request Dispatcher

Requests are dispatched to a single request handler and this can be done through a dispatcher.

publicstaticvoidmain(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.ApplicationContextapplicationContext =springApplicationContext();// Deezpatch implements the Dispatcher interface.Dispatcherdispatcher =Deezpatch.builder()        .instanceProvider(applicationContext::getBean)        .requests(config ->config.handlers(GreetCommandHandler.java,PingQueryHandler.java        ))        .build();// Send command!dispatcher.send(newGreetCommand("Deez"));// Send query!Optional<Pong>pong =dispatcher.send(newPingQuery());}

✉️ Events

Events are messages that indicate that something has occurred in the system.

publicclassGreetedEventimplementsEvent {privatefinalStringgreeting;publicGreetedEvent(Stringgreeting) {this.greeting =greeting;    }publicStringgreeting() {returngreeting;    }}

📨 Event Handlers

Events are handled by event handlers. Event handlers can be registered through the use of the@EventHandler annotation.

An event can have zero or more event handlers.

publicclassGreetedEventHandler {@EventHandlerpublicvoidsayHello(GreetedEventevent) {// Well, hello!    }@EventHandlerpublicvoidsayKumusta(GreetedEventevent) {// Well, kumusta?    }@EventHandlerpublicvoidsayGotEm(GreetedEventevent) {// Got 'em!    }}

📣 Event Publisher

Events are dispatched to zero or more event handlers and this can be done through a publisher.

publicstaticvoidmain(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.ApplicationContextapplicationContext =springApplicationContext();// Deezpatch implements the Publisher interface.Publisherpublisher =Deezpatch.builder()        .instanceProvider(applicationContext::getBean)        .events(config ->config.handlers(GreetedEventHandler.java        ))        .build();// Publish event!publisher.publish(newGreetedEvent("Hi from Deez!"));}

🔩 Easy Integration with Dependency Injection (DI) Frameworks

The library provides anInstanceProvider interface as an extension point to let users customize how request/event handler instances should be instantiated. This can be as simple asnew-ing up request/event handlers or getting instances from a DI framework such as Spring'sApplicationContext, Guice'sInjector, etc.

Example with No DI framework

// Application.javapublicstaticvoidmain(String[]args) {Deezpatchdeezpatch =Deezpatch.builder()      .instanceProvider(Application::getInstance)      .requests(...)      .events(...)      .build();}privatestaticObjectgetInstance(Class<?>handlerType) {if (MyRequestHandler.class.equals(handlerType)) {returnnewMyRequestHandler();  }elseif (MyEventHandler.class.equals(handlerType)) {returnnewMyEventHandler();  }thrownewIllegalStateException("Failed to get instance for " +handlerType.getName() +".");}

Example with Spring's ApplicationContext

publicstaticvoidmain(String[]args) {ApplicationContextapplicationContext =springApplicationContext();Deezpatchdeezpatch =Deezpatch.builder()      .instanceProvider(applicationContext::getBean)      .requests(...)      .events(...)      .build();}

Example with Guice's Injector

publicstaticvoidmain(String[]args) {Injectorinjector =guiceInjector();Deezpatchdeezpatch =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-inRequestHandler andEventHandler 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.

// Let's say below classes are declared in a project's core/domain package:@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interfaceAwesomeRequestHandler {}@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interfaceAwesomeEventHandler {}publicclassMyRequestHandler {@AwesomeRequestHandlerpublicvoidhandle(TestRequestrequest) {// Handle.  }}publicclassMyEventHandler {@AwesomeEventHandlerpublicvoidhandle(TestEventevent) {// Handle.  }}// To wire things up:publicstaticvoidmain(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.ApplicationContextapplicationContext =springApplicationContext();// Register handlers and custom annotations.Deezpatchdeezpatch =Deezpatch.builder()      .instanceProvider(applicationContext::getBean)      .requests(config ->config.handlerAnnotations(AwesomeRequestHandler.class)              .handlers(MyRequestHandler.class))      .events(config ->config.handlerAnnotations(AwesomeEventHandler.java)              .handlers(MyEventHandler.class))      .build();}

🎛️ Custom Invocation Strategies

The library providesDeezpatch.RequestHandlerInvocationStrategy andDeezpatch.EventHandlerInvocationStrategy interfaces as extension points to let users customize how request/event handler methods are invoked by the Dispatcher and Publisher.

Built-in implementations are:

Users can create a new implementation and override the defaults by:

// Register custom invocation strategy.Deezpatchdeezpatch =Deezpatch.builder()    .requests(config ->config.invocationStrategy(newLoggingInvocationStrategy(newRetryOnErrorInvocationStrategy())))    .events(config ->config.invocationStrategy(newLoggingInvocationStrategy(newOrderGuaranteedInvocationStrategy())))      .build();

SonarQube Cloud

About

A simple yet 🗲FAST🗲 library to dispatch requests and events to corresponding handlers 🚀

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors4

  •  
  •  
  •  
  •  

[8]ページ先頭

©2009-2025 Movatter.jp