Method and system for code structure optimization based on domain events and event sourcing
By optimizing the code structure through domain-driven design and event sourcing, the problem of business logic complexity caused by the object anemicity model in the traditional J2EE model is solved, realizing the decoupling and scalability of the system, and providing the ability to trace events and restore historical states.
Patent Information
- Application Number
- CN202210133488.X
- Authority / Receiving Office
- CN · China
- Patent Type
- Patents(China)
- Current Assignee / Owner
- Filing Date
- 2022-02-14
- Publication Date
- 2026-01-16
- Estimated Expiration
- 2042-02-14
AI Technical Summary
In the traditional J2EE Action/Service/DAO layered model, the anemic domain model, where objects are used as data carriers, results in high complexity of business logic and makes it difficult to maintain.
It adopts domain-driven design, optimizes code structure through aggregation and domain events, uses EventBus to distribute events, combines Disruptor and MQ components for event storage and forwarding, and uses aggregate roots to rebuild state, achieving event sourcing and eventual consistency.
It reduces the complexity of business logic, improves the scalability and cohesion of the system, realizes event-driven decoupling and asynchronous message passing, and has auditing capabilities and historical state recovery functions.
Smart Images

Figure CN114490410B_ABST
Abstract
Description
TECHNICAL FIELD
[0001] The present application relates to the technical field of data processing, in particular to a code structure optimization method and system based on domain events and event traceability. BACKGROUND
[0002] Under the traditional J2EE Action / Service / DAO layered thought mode, the object is only a carrier of data, only has data fields and Get / Set methods, and has no logic in the object. Such a data model is referred to as a "anemic model" in domain-driven design. As the project becomes more complex, the business logic and state are scattered in a large number of methods, and the original code intent is gradually unclear. We call this situation "anemic model-induced amnesia".
[0003] In order to solve this problem, according to the idea of domain-driven design, the business logic complexity can be reduced, a "rich model" and "aggregation" can be constructed, and a "domain event" can be used to describe and process the behavior in the business model. In this way, the process of processing can be decoupled, the scalability of the system can be realized, and the cohesion of the main business process can be improved.
[0004] How to reduce the complexity of business logic is a technical problem to be solved. SUMMARY
[0005] The technical task of the present application is to provide a code structure optimization method and system based on domain events and event traceability to solve the technical problem of how to reduce the complexity of business logic in view of the above shortcomings.
[0006] In a first aspect, the code structure optimization method based on domain events and event traceability of the present application comprises the following steps:
[0007] Under the triggering of a command, an event with a unique identifier is created through aggregation or a domain service, and the event is packaged in an EventMessage;
[0008] Based on the observer pattern, the event is distributed to an event subscriber through an EventBus, and the event subscriber includes an event storage subscriber, an instant forwarding subscriber, and other subscribers;
[0009] For the event, the event is forwarded and stored in a database through the event storage subscriber, the event is forwarded to a message queue through the instant forwarding subscriber, and the event in the database is forwarded to the message queue through a forwarder;
[0010] Based on a series of events generated by the aggregation, the state of the aggregation is reconstructed through the aggregate root.
[0011] As a preferred, the aggregation is a collection of a group of related objects, which is accessed as a whole by the outside world.
[0012] The aggregation has the following principles: having a unique identifier, being a small aggregation, referencing other aggregations by unique identifier, using eventual consistency outside the aggregation boundary, and the small aggregation means that the number of objects as a collection is less than a threshold.
[0013] As a preferred, the event is wrapped in an EventMessage, which includes an identifier for identifying the event, a message type for identifying the event source, event metadata, a payload, and a timestamp.
[0014] As a preferred, in the Java project, the @CommandHandler annotation is used for the command, the annotated method is saved in the memory through reflection, the command name is used as the key, and the annotated method is used as the value. When the command bus accepts the command, the corresponding method is taken out in the memory to call.
[0015] As a preferred, after the event is forwarded to the database by the event storage subscriber, the event is serialized, and the event is stored in the database based on the sequence form of the event and the event metadata.
[0016] As a preferred, the event is distributed and saved to the storage database in a distributed manner through the Disruptor component, and the event is distributed to the instant forwarding subscriber through the MQ component.
[0017] As a preferred, the EventBus is used as an event bus, an interceptor is configured on the event bus, additional processing is added to the command, and the type or name of the command does not need to be considered, including logging, security / authorization, monitoring, and load balancing.
[0018] As a preferred, when the number of alive events of an aggregation exceeds a threshold, and the state of the aggregation is constantly changing, the aggregation causes multiple events, the multiple events are summarized into a single event by periodically creating and storing a snapshot event, and the state of the aggregation is reconstructed by the aggregate root based on the single event.
[0019] In a second aspect, the code structure optimization system based on domain events and event traceability provided by the present application executes the code structure optimization method based on domain events and event traceability as described in any one of the first aspect, and the system comprises:
[0020] The configuration module is configured to create and configure an aggregation and a domain service. The aggregation is a collection of a group of related objects, and is externally as a whole. The aggregation has the following principles: having a unique identifier, being a small aggregation, referencing other aggregations by unique identifier, using eventual consistency outside the aggregation boundary, and the small aggregation means that the number of objects as a collection is less than a threshold.
[0021] an event creation module, which interacts with the event creation module, for creating an event with a unique identifier by an aggregate or a domain service under the triggering of a command, wrapping the event in an EventMessage, the EventMessage including an identifier for identifying the event, a message type for identifying the event source, event metadata, a payload, and a timestamp;
[0022] an event distribution module, which interacts with the event creation module, for distributing the event to event subscribers including an event storage subscriber, an instant forwarding subscriber, and other subscribers by an EventBus based on an observer pattern, the EventBus including a Disruptor component for distributing the event to a database and serializing the event, storing the event in the database based on a serial form of the event and the event metadata, an MQ component for distributing the event to the instant forwarding subscriber, and other components for distributing the event to the other subscribers;
[0023] a database, which interacts with the data distribution module, for storing the event;
[0024] a forwarder, which interacts with the database, for forwarding the event;
[0025] a message queue, which interacts with the event distribution module and the forwarder, for forwarding the event to a remote subscriber;
[0026] an aggregate reconstruction module, which is used for reconstructing a state of an aggregate by an aggregate root based on a series of events generated by the aggregate.
[0027] Preferably, in a Java project, the event creation module is used for using a @CommandHandler annotation for a command, saving an annotated method in a memory by reflection, taking the command name as a key and the annotated method as a value, and calling the corresponding method in the memory when a command accepted by the command bus;
[0028] the EventBus is used as an event bus, an interceptor is configured on the event bus, additional processing is added to the command, and the type or name of the command does not need to be considered, including logging, security / authorization, monitoring, and load balancing;
[0029] When the aggregated live events exceed a threshold and the state of the aggregation is constantly changing, the aggregation triggers multiple events, and the aggregation re-modeling module is configured to summarize the multiple events into a single event by periodically creating and storing snapshot events, and based on the single event, reconstruct the state of the aggregation through the aggregation root.
[0030] The code structure optimization method and system based on domain events and event traceability have the following advantages:
[0031] 1. Using event-driven can further reduce the coupling between systems and make it easier to achieve Serverless; if a system has a bug, the correct value can be traced according to historical events;
[0032] 2. Event-driven is naturally auditable, and no separate audit log module is needed, so the history of executed commands and the events caused by the commands in each subsystem can be easily queried;
[0033] 3. Read and write can be more thoroughly isolated. If the traditional write method accidentally calls update in find / get, the implicit side effects often cause very difficult-to-find bugs. Everything based on the command and event thinking can eliminate the uncertain side effects caused by unclear read-write responsibilities. BRIEF DESCRIPTION OF DRAWINGS
[0034] In order to more clearly illustrate the technical solutions in the embodiments of the present application, the following will briefly introduce the drawings needed to be used in the embodiments or prior art description. Obviously, the drawings in the following description are only some embodiments of the present application, and for those skilled in the art, other drawings can also be obtained without creative labor based on these drawings.
[0035] The present application will be further described below in conjunction with the drawings.
[0036] Figure 1 The workflow block diagram of the code structure optimization method based on domain events and event traceability for embodiment 1. DETAILED DESCRIPTION
[0037] The present application will be further described below in conjunction with the drawings and specific embodiments, so that those skilled in the art can better understand the present application and implement it. However, the embodiments are not limiting to the present application, and the technical features in the embodiments and the embodiments can be combined with each other without conflict.
[0038] The present application provides a code structure optimization method and system based on domain events and event traceability, which is used to solve the technical problem of how to reduce the complexity of business logic.
[0039] Embodiment 1:
[0040] The application is based on a code structure optimization method of domain events and event traceability, comprising the following steps:
[0041] S100, under the triggering of a command, an event with a unique identifier is created by an aggregate or a domain service, and the event is wrapped in an EventMessage;
[0042] S200, based on the observer pattern, the event is distributed to event subscribers by EventBus, and the event subscribers include event storage subscribers, instant forwarding subscribers and other subscribers;
[0043] S300, for the event, the event is forwarded and stored in the database by the event storage subscriber, the event is forwarded to the message queue by the instant forwarding subscriber, and the event in the database is forwarded to the message queue by the forwarder;
[0044] S400, based on the series of events generated by the aggregate, the state of the aggregate is reconstructed by the aggregate root.
[0045] In this embodiment, Aggregate (aggregate) is a collection of related objects, which is accessed as a whole by the outside world. A well-designed aggregate should follow the following principles:
[0046] 1. has a unique identifier;
[0047] 2, design small aggregates as much as possible;
[0048] 3, reference other aggregates through unique identifier;
[0049] 4, use eventual consistency outside the aggregate boundary.
[0050] In actual projects, there are also a large number of behaviors that do not belong to aggregates, that is, static methods, instead of letting them scattered in various places of the project, it is better to make them into unified services, that is, "domain services". Events are created by aggregates or domain services.
[0051] Command, which is used to describe the intention to change the state of the application, can be designed as an immutable POJO in the application. The command always has an exact destination, although the sender does not care which service handles the command or where the service resides, but it is interested in the result, so we set a callback function for the command, which allows the result to be returned after the command is sent.
[0052] In step S100, when the aggregate or domain service receives a "command", it will raise an event. In a specific implementation, it is wrapped in an EventMessage. The most important thing about an event is its unique identifier, in addition to the message type identifying the source of the event, event metadata, payload, and timestamp.
[0053] In a Java project, you can use annotations for development. For commands, we use the @CommandHandler annotation, and then save the annotated method in memory through reflection, generally with the command name as the key and the annotated method as the value. Then when the command bus accepts a command, it takes the corresponding method from memory to call.
[0054] The domain event is built as follows:
[0055]
[0056]
[0057] Events are the core, which are objects that describe something that has happened in the application. They are usually triggered by "commands". When something important happens in the aggregate, it will raise an event. Events can be any object, which can be serialized and persisted. When the event is distributed, it is encapsulated in an EventMessage, and then distributed to various event subscribers through an event dispatcher. Depending on the different functions of the subscribers, events are processed differently.
[0058] Step S200 is the distribution of events. In a specific implementation, the publication of events uses the Observer pattern, which can achieve decoupling of the model and external components. Several event publishers and event subscribers with different functions can be implemented according to project requirements, such as event storage subscribers, immediate forwarding subscribers, and other subscribers.
[0059] EventBus is a mechanism for distributing events to handlers that subscribe to the event. It supports subscribing and tracking event processing results, and can also persist events, which allows them to be replayed at a later stage.
[0060] With the help of the Disruptor component, distributed event publishing and storage functions are achieved. With the help of some MQ components, it is published to various MQ message queues to achieve distributed transaction publishing.
[0061] EventBus is an event bus on which interceptors can be configured to add additional processing to commands, regardless of their type or name, such as logging, security (authorization), monitoring, load balancing, etc.
[0062] Step S300 is the storage of events and the forwarding of events.
[0063] Stored events must have a unique identifier. In one particular implementation, events are serialized after being forwarded to the database by the event storage subscriber, and stored in the database based on the serialized form of the event and the event metadata.
[0064] Events in the message queue have two sources. One is to forward the events stored in the database to the message queue through the forwarder, and the other is to forward the events to the message queue through the immediate forwarding subscriber. The message queue can distribute the events to remote subscribers.
[0065] Step S400 is the reconstruction of aggregates based on events.
[0066] Aggregate roots can reconstruct their state from events, or they can be configured to be loaded from an event source store. These stores do not store the aggregates themselves, but a series of events generated by the aggregates. Based on these events, the state of the aggregates can be restored at any time.
[0067] The JpaEventStorageEngine is used to store events in a jpa-compatible data source. The JPA event store stores events in so-called entries. These entries contain the serialized form of the event, as well as some fields that store metadata to quickly find the entries.
[0068] When aggregates live for a long time and their state changes constantly, they will generate a large number of events. Loading all these events to reconstruct a state of an aggregate can have a significant performance impact. Snapshot events are domain events with a special purpose: they summarize an arbitrary number of events into a single event. By creating and storing snapshot events periodically, the event store does not need to return long lists of events. It only needs to return the last snapshot event and all events that occurred after the snapshot.
[0069] The creation of snapshots can be triggered by many factors, such as the number of events created since the last snapshot, the time since the initialization of the aggregate exceeds a certain threshold, based on time, etc.
[0070] When an aggregate lives for more than a threshold and its state changes constantly, the aggregate raises multiple events, which are summarized into a single event by creating and storing snapshot events periodically, and based on the single event, the state of the aggregate is reconstructed by the aggregate root.
[0071] This embodiment's method, based on the principles of Domain-Driven Design, reduces business logic complexity and constructs a "rich model" and "aggregates." It uses "domain events" to describe and process behaviors within the business model. This decouples the processing flow, improves system scalability, and enhances the cohesion of the main business process. This method achieves the following objectives:
[0072] First, it decouples business processes from modules, so that event publishers and subscribers do not need to know about each other's existence in advance.
[0073] Second, asynchronous message passing allows business logic and events to occur synchronously.
[0074] Third, many-to-many interaction enables a distributed publish-subscribe model.
[0075] Fourth, it enables the architecture to persist historical commands and execution results, and allows historical states to be restored through snapshots.
[0076] Example 2:
[0077] This invention relates to a code structure optimization system based on domain events and event sourcing, comprising a configuration module, an event creation module, an event distribution module, a database, a forwarder, a message queue, and an aggregation and reconstruction module. This module can execute the method disclosed in Embodiment 1.
[0078] The configuration module is used to create and configure aggregates and domain services. An aggregate is a collection of related objects that are presented externally as a whole and follows these principles: it has a unique identifier, is a small aggregate, references other aggregates through a unique identifier, and uses eventual consistency outside the aggregate boundary. A small aggregate is understood as a collection whose number of objects is less than a threshold.
[0079] In a specific implementation, an aggregation is a collection of related objects that is accessed as a whole. A well-designed aggregation should adhere to the following principles:
[0080] 1. It has a unique identifier;
[0081] 2. Design smaller aggregates whenever possible;
[0082] 3. Referencing other aggregates using unique identifiers;
[0083] 4. Use eventual consistency outside of aggregation boundaries.
[0084] In real-world projects, there are also many behaviors that don't belong to aggregates, namely static methods. Instead of letting them be scattered throughout the project, it's better to make them into a unified service, or "domain service." Events are created by aggregates or domain services.
[0085] Command, is used to describe the intention to change the application state, in the application can be designed as a command immutable POJO. Command always has a specific destination, although the sender does not care which service to handle the command or the service where it resides, but it is interested in its results, so we will set the callback function for the command, after the command is sent to allow the return result.
[0086] Event creation module interacts with the event creation module, for the creation of a unique identifier event by aggregation or domain service under the command of the trigger, the event is wrapped in an EventMessage, the EventMessage includes the identifier for identifying the event, message type for identifying the event source, event metadata, payload and timestamp.
[0087] In a specific implementation, when the aggregate or domain service receives the "command", an event will be triggered and wrapped in an EventMessage. The most important event is its unique identifier, in addition to the message type, event metadata, payload and timestamp.
[0088] In the Java project, you can use annotations for development. For the command we use @CommandHandler annotation, and then through reflection to save the annotated method in memory, generally with the command name as the key, the annotated method as the value. Then when the command bus accepts the command, the corresponding method is taken out from the memory to call.
[0089] The domain event construction method is as follows:
[0090]
[0091]
[0092] Event is the core, which is an object that describes what has happened in the application. Usually triggered by "command". When something important happens in the aggregate, it will trigger an event. Event can be any object, which can be serialized and persisted. When the event is distributed, we will encapsulate it in an EventMessage, and then distribute it to each event subscriber through the event distribution module. According to the different functions of each subscriber, the event is treated differently.
[0093] The event distribution module interacts with the event creation module to distribute events to event subscribers, including event storage subscribers, immediate forwarding subscribers, and other subscribers, based on an observer pattern through an EventBus, which includes a Disrutor component, an MQ component, and other components. The Disrutor component is used to distribute events to a database and serialize events, store events in the database based on event serialization and event metadata, the MQ component is used to distribute events to immediate forwarding subscribers, and the other components are used to distribute events to other subscribers.
[0094] The publication of events uses an observer (Observer) pattern, which can decouple the model from external components. Several event publishers and event subscribers with different functions, such as event storage subscribers, immediate forwarding subscribers, and other subscribers, can be implemented according to project requirements.
[0095] EventBus is a mechanism for distributing events to handlers that subscribe to the event. It supports event subscription and tracking of event processing results, and can also persist events, which allows them to be replayed at a later stage.
[0096] With the Disruptor component, distributed event publishing and storage functions are implemented. With some MQ components, events are published to various MQ message queues to implement distributed transaction publishing.
[0097] EventBus is an event bus, on which interceptors can be configured to add additional processing to commands without considering their types or names, such as logging, security (authorization), monitoring, load balancing, etc.
[0098] The database interacts with the data distribution module to store events. Events that implement storage must have a unique identifier. In a specific implementation, events are serialized after being forwarded to the database by the event storage subscriber, and stored in the database based on event serialization and event metadata. That is, the event content in the database includes event serialization and event metadata.
[0099] The message queue interacts with the event distribution module and the forwarder to forward events to remote subscribers. That is, there are two sources of events in the message queue. One is to forward the stored events in the database to the message queue through the forwarder, and the other is to forward the events to the message queue through the immediate forwarding subscriber, which can distribute events to remote subscribers.
[0100] The aggregate reconstruction module is used to reconstruct the state of the aggregate based on the series of events generated by the aggregate.
[0101] A polyglot root is able to reconstruct their state from events, but can also be configured to be loaded through an event source repository. These repositories do not store the aggregates themselves, but store a sequence of events generated by the aggregates. Based on these events, the state of the aggregates can be restored at any time.
[0102] The JpaEventStorageEngine is used to store events in a jpa compatible data source. The JPA event store stores events in so called entries. These entries contain the serialized form of the event, as well as some fields storing metadata to quickly find these entries.
[0103] When aggregates live a long time, and their state changes constantly, they will produce a large number of events. Loading all these events to reconstruct the state of an aggregate can have a big performance impact. A snapshot event is a domain event with a special purpose: it summarizes an arbitrary number of events into a single event. By creating and storing snapshot events periodically, the event store does not need to return a long list of events. It only needs to return the last snapshot event, and all events that occurred after the snapshot.
[0104] The creation of a snapshot can be triggered by many factors, for example the number of events created since the last snapshot, the time since the initialization of the aggregate exceeds a certain threshold, based on time, etc.
[0105] The above detailed description of the present application is made by the accompanying drawings and preferred embodiments, however the present application is not limited to these disclosed embodiments, and those skilled in the art can know that the code review means in different embodiments described above can be combined to obtain more embodiments of the present application, and these embodiments are also within the protection scope of the present application.
Claims
1. A method for code structure optimization based on domain events and event sourcing, characterized in that It comprises the following steps: Under the initiation of a command, an event with a unique identifier is created by an aggregate or a domain service, the event is wrapped in an EventMessage, the aggregate is a collection of a group of related objects, which is accessed as a whole by the outside world, the aggregate has the following principles: has a unique identifier, is a small aggregate, references other aggregates by a unique identifier, uses eventual consistency outside the aggregate boundary, the small aggregate means that the number of objects as a collection is less than a threshold value; the event is wrapped in an EventMessage, which includes an identifier for identifying the event, a message type for identifying the event source, event metadata, a payload, and a timestamp; in a Java project, a @CommandHandler annotation is used for a command, an annotated method is saved in memory by reflection, a command name is used as a key, and an annotated method is used as a value, when a command bus accepts a command, a corresponding method is taken out from memory to be called; Based on the observer mode, events are distributed to event subscribers by an EventBus, the event subscribers include an event storage subscriber, an instant forwarding subscriber, and other subscribers; For events, events are forwarded and stored in a database by an event storage subscriber, events are forwarded to a message queue by an instant forwarding subscriber, and events in the database are forwarded to the message queue by a forwarder; wherein after events are forwarded to the database by the event storage subscriber, the events are serialized, and the events are stored in the database based on the serial form of the events and event metadata; events are distributed and saved to a storage database in a distributed manner by a Disruptor component, and events are distributed to an instant forwarding subscriber by an MQ component; the EventBus is used as an event bus, an interceptor is configured on the event bus, additional processing is added to a command, and the type or name of the command does not need to be considered, including log recording, security / authorization, monitoring, and load balancing; Based on a series of events generated by an aggregate, the state of the aggregate is reconstructed by an aggregate root, when the number of live events of the aggregate exceeds a threshold value, and the state of the aggregate constantly changes, the aggregate initiates multiple events, the multiple events are summarized into a single event by creating and storing a snapshot event periodically, and the state of the aggregate is reconstructed by the aggregate root based on the single event.
2. A system for code structure optimization based on domain events and event sourcing, characterized in that The method for optimizing the code structure based on domain events and event tracing according to claim 1, the system comprises: A configuration module is configured to create and configure aggregates and domain services, the aggregate is a collection of a group of related objects, which is accessed as a whole, and has the following principles: has a unique identifier, is a small aggregate, references other aggregates by a unique identifier, and uses eventual consistency outside the aggregate boundary, the small aggregate means that the number of objects as a collection is less than a threshold value; An event creation module, which interacts with the configuration module, is configured to create an event with a unique identifier by an aggregate or a domain service under the triggering of a command, wrap the event in an EventMessage, and include an identifier for identifying the event, a message type for identifying a source of the event, event metadata, a payload, and a timestamp in the EventMessage; An event distribution module, which interacts with the event creation module, is configured to distribute the event to event subscribers including an event storage subscriber, an instant forwarding subscriber, and other subscribers by an EventBus based on an observer pattern, and the EventBus includes a Disruptor component for distributing the event to a database, serializing the event, and storing the event in the database based on a serialized form of the event and event metadata, an MQ component for distributing the event to the instant forwarding subscriber, and other components for distributing the event to the other subscribers; A database, which interacts with the event distribution module, is configured to store the event; A forwarder, which interacts with the database, is configured to forward the event; A message queue, which interacts with the event distribution module and the forwarder, is configured to forward the event to a remote subscriber; An aggregate reconstruction module is configured to reconstruct a state of an aggregate by an aggregate root based on a series of events generated by the aggregate; In a Java project, the event creation module is configured to use a @CommandHandler annotation for a command, save an annotated method in a memory by reflection, use a command name as a key and the annotated method as a value, and call the corresponding method in the memory when a command accepted by a command bus. The EventBus is configured as an event bus, and an interceptor is configured on the event bus to add additional processing to the command without considering a type or a name of the command, including logging, security / authorization, monitoring, and load balancing. When an event of an aggregate exceeds a threshold value and a state of the aggregate is constantly changed, the aggregate triggers a plurality of events, and the aggregate reconstruction module is configured to summarize the plurality of events into a single event by periodically creating and storing a snapshot event, and reconstruct the state of the aggregate by the aggregate root based on the single event.
Citation Information
Patent Citations
Domain-driven design tactical modeling method
CN113326027A