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 Quarkus extension for easy implementation of domain-driven design

License

NotificationsYou must be signed in to change notification settings

MatthiasSchupp/ddq

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

86 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Quarkus extension for domain-driven Microservices.

  • Following Domain-driven design principles:The extension offers different features to support the development of Microservices according to domain-driven designfollowing the bookImplementing Domain-Driven Design fromVaughn Vernon.
  • All optional:It is an extension, not a framework. With it you can use the different features you like, but you are not forced to.

To benefit from this extension it is necessary to understand the principles and tactical patterns of domain-driven design.

Usage

To create a Quarkus application using this extension and get the right configuration and plugins, the archetype can beused. There is also an example application in the repository to provide some code.

mvn archetype:generate -DarchetypeGroupId=eu.domain-driven -DarchetypeArtifactId=ddq-archetype -DarchetypeVersion=<version>

Features

Domain events

The extension ensures the publishing, collection and correct processing of domain events, also with multiple instancesof the same service running at the same time.To make this possible, each event will first written to the database and then processed from there. This ensures thedecoupling and transactional security of event processing.

Publish events

In CDI beans:

@DependendpublicclassExampleService {@InjectEventPublishereventPublisher;publicvoiddoBusinessStuff(StuffIdstuffId) {// Do some stuff hereeventPublisher.publish(newStuffDone(stuffId));    }}

In Pojo classes:

publicclassExample {publicvoiddoBusinessStuff(StuffIdstuffId) {// Do some stuff hereEvents.publish(newStuffDone(stuffId));    }}

In the domain model:

@javax.persistence.EntitypublicclassExampleextendsEntity {@EmbeddedprivateStuffIdstuffId;publicvoiddoBusinessStuff() {// Do some stuff herepublishEvent(newStuffDone(stuffId));    }}

Consume events

In CDI beans:

@DependendpublicclassExampleService {voidonStuffDone(@ObservesStuffDonestuffDone) {// Do some other stuff here    }}

Publish events to other applications

All events published in the application and collected from other applications are available via REST as notifications

http://hostname[:port]/example/resources/notifications/events

Collect events from other application

To collect events from other applications using this extension, an event source must be defined in theapplication.properties file.Valid url formats are:

For an event source, a start id can be defined, which sets the oldest event to collect. Without a start id, thecollection begins with the actual newest event.

quarkus.ddq.event.event-source.<name>.uri=hostname/examplequarkus.ddq.event.event-source.<name>.start-id=0#optional

Errors

To provide a better insight in the errors occurred during of the processing of the application than simply write it in anunstructured logfile,the extension provides the errors similar to the events.

Publish errors

In CDI beans:

@DependendpublicclassExampleService {@InjectErrorPublishererrorPublisher;publicvoiddoBusinessStuff(StuffIdstuffId) {// Do some stuff hereerrorPublisher.business("Error Message");try {// Do some stuff here        }catch (SomeExceptione) {errorPublisher.technical("Error Message",e);        }    }}

In Pojo classes:

publicclassExample {publicvoiddoBusinessStuff(StuffIdstuffId) {// Do some stuff hereErrors.business("Error Message",this.getClass());// orErrors.publisher(this.getClass()).business("Error Message");try {// Do some stuff here        }catch (SomeExceptione) {Errors.technical("Error Message",this.getClass(),e);        }    }}

Domain model

There are some base classes available to easily implement the domain model:

  • ValueObject
  • UUIDValueObject
  • IdentifiedValueObject
  • IdentifiedDomainObject
  • Entity

HATEOAS REST resources

HATEOAS REST endpoint with ETag support can be implemented as follows:

@BasePath(GreetingsResource.PATH)publicclassGreetingRepresentationimplementsRepresentation {privatefinalGreetingIdgreetingId;privatefinalPersonperson;privatefinalIntegersalutes;@JsonbTransientprivatefinalStringpersonName;@BaseLink(rel ="self",path ="{greetingId}")privateLinkselfLink;@BaseLink(rel ="person",queryParams =@QueryParam(name ="name",values ="{personName}"))privateLinkpersonLink;@BaseLink(rel ="salute",path ="{greetingId}/salute",condition ="maxSalutesNotReached")privateLinksaluteLink;@BaseLink(rel ="salutes",path ="{greetingId}/salutes")privateLinksalutesLink;publicGreetingRepresentation(Greetinggreeting) {this.greetingId =greeting.greetingId();this.person =greeting.person();this.salutes =greeting.salutes();this.personName =person.name();    }publicbooleanmaxSalutesNotReached() {returnsalutes <100;    }@Overridepublicbooleanequals(Objecto) {if (this ==o)returntrue;if (o ==null ||getClass() !=o.getClass())returnfalse;GreetingRepresentationthat = (GreetingRepresentation)o;returngreetingId.equals(that.greetingId) &&person.equals(that.person) &&salutes.equals(that.salutes);    }@OverridepublicinthashCode() {returnObjects.hash(greetingId,person,salutes);    }}
publicclassGreetingLogRepresentationextendsLogRepresentation {@BaseLink(path ="greetings/salutes")privateLinksalutes;publicGreetingLogRepresentation(Collection<Greeting>greetings) {super(greetings,"greetings",GreetingRepresentation::new);    }}
@Path(GreetingsResource.PATH)@Produces(MediaType.APPLICATION_JSON)@Consumes(MediaType.APPLICATION_JSON)@TransactionalpublicclassGreetingsResource {publicstaticfinalStringPATH ="greetings";@InjectGreetingServicegreetingService;@InjectEntityTagResponseFactoryresponseFactory;@GETpublicResponsegreetings(@QueryParam("name")StringpersonName) {returnpersonName !=null                ?greetingService.greeting(newPerson(personName))                        .map(greeting ->responseFactory.createResponse(Collections.singletonList(greeting),GreetingLogRepresentation::new))                        .orElse(Response.status(NOT_FOUND).build())                :responseFactory.createResponse(greetingService.greetings(),GreetingLogRepresentation::new);    }@GET@Path("{id}")publicResponsegreeting(@PathParam("id")Stringid) {returngreetingService.greeting(newGreetingId(id))                .map(greeting ->responseFactory.createResponse(greeting,GreetingRepresentation::new))                .orElse(Response.status(NOT_FOUND).build());    }}

About

A Quarkus extension for easy implementation of domain-driven design

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Languages


[8]ページ先頭

©2009-2026 Movatter.jp