Axon 参考指南
  • 介绍
  • 架构概览
    • DDD & CQRS 概念
    • 事件溯源
    • 事件驱动的微服务
  • Axon Server
  • 发行说明
    • Axon Framework
      • Major Releases
      • Minor Releases
    • Axon Server
      • Major Releases
      • Minor Releases Standard Edition
      • Minor Releases Enterprise Edition
    • Axon Framework Extensions
      • AMQP
        • Major Releases
      • CDI
        • Major Releases
      • JGroups
        • Major Releases
      • Kafka
        • Major Releases
        • Minor Releases
      • Kotlin
        • Experimental Releases
      • Mongo
        • Major Releases
        • Minor Releases
      • Reactor
        • Major Releases
        • Minor Releases
      • Spring Cloud
        • Major Releases
        • Minor Releases
      • Tracing
        • Major Releases
        • Minor Releases
  • Getting Started
    • 快速开始
  • Axon Framework
    • 介绍
    • 消息传递概念
      • 消息剖析
      • 消息关联
      • 消息拦截
      • 支持带注解的处理程序
      • 异常处理
      • 工作单元
    • 命令
      • 建模
        • 聚合
        • 多实体聚合
        • 聚合状态存储
        • 从另一个聚合创建聚合
        • 聚合多态性
        • 解决冲突
      • 命令调度器
      • 命令处理程序
      • 基础设施
      • 配置
    • 事件
      • 事件调度器
      • 事件处理程序
      • 事件处理器
        • 订阅事件处理器
        • 流式事件处理器
      • 事件总线和事件存储
      • 事件版本控制
    • 查询
      • 查询处理
      • 查询调度器
      • 查询处理程序
      • 实现
      • 配置
    • 长时处理过程(Sagas)
      • 实现
      • 关联
      • 基础设施
    • Deadlines
      • Deadline Managers
      • Event Schedulers
    • 测试
      • 命令 / 事件
      • 长时处理过程(Sagas)
    • 序列化
    • 调整
      • 事件快照
      • 事件处理
      • 命令处理
    • 监控和指标
    • Spring Boot 集成
    • 模块
  • Axon Server
    • 介绍
    • 安装
      • 本地安装
        • Axon Server SE
        • Axon Server EE
      • Docker / K8s
        • Axon Server SE
        • Axon Server EE
    • 管理
      • 配置
        • System Properties
        • Command Line Interface
        • REST API
        • GRPC API
      • Monitoring
        • Actuator Endpoints
        • gRPC Metrics
        • Heartbeat Monitoring
      • Clusters
      • Replication Groups
      • Multi-Context
      • Tagging
      • Backup and Messaging-only Nodes
      • Backups
      • Recovery
      • Plugins
      • Error Codes
    • 安全
      • SSL
      • 访问控制
      • 访问控制 - 标准版
      • 访问控制 - 企业版
      • 访问控制 - 客户端应用程序
      • 访问控制 - 命令行
      • 访问控制 - REST API
      • 访问控制 - LDAP
      • 访问控制 - OAuth 2.0
    • 性能
      • 事件段
      • 流量控制
    • 迁移
      • Standard to Enterprise Edition
      • Non-Axon Server to Axon Server
  • Extensions
    • Spring AMQP
    • JGroups
    • Kafka
    • Kotlin
    • Mongo
    • Reactor
      • Reactor Gateways
    • Spring Cloud
    • Tracing
  • Appendices
    • A. RDBMS Tuning
    • B. Message Handler Tuning
      • 参数解析器
      • 处理程序增强
    • C. 元数据注解
    • D. 标识符生成
    • E. Axon Server Query Language
由 GitBook 提供支持
在本页
  • Aggregate Configuration
  • Registering a Command Handler
  • Command Model Repositories
  • Standard Repositories
  • Event Sourcing Repositories
  • Aggregate Factories
  • GenericAggregateFactory
  • SpringPrototypeAggregateFactory
  • Implementing your own Aggregate Factory
  1. Axon Framework
  2. 命令

配置

Configuration

上一页基础设施下一页事件

最后更新于2年前

This page aims to describe the suite of options for configuring the Command Model.

Aggregate Configuration

Core concepts within the Command Model are the which are implemented. To instantiate a default Aggregate configuration you simply do the following:

Configurer configurer = DefaultConfigurer.defaultConfiguration()
       .configureAggregate(GiftCard.class);
}

The @Aggregate annotation (in the org.axonframework.spring.stereotype package) triggers auto configuration to set up the necessary components to use the annotated type as an aggregate. Note that only the aggregate root needs to be annotated.

Axon will automatically register all the @CommandHandler annotated methods with the command bus and set up a repository if none is present.

// ...
import org.axonframework.spring.stereotype.Aggregate;
// ...
@Aggregate
public class GiftCard {
    @AggregateIdentifier
    private String id;

    @CommandHandler
    public GiftCard(IssueCardCommand cmd) {
       apply(new CardIssuedEvent(cmd.getCardId(), cmd.getAmount()));
    }
}

Registering a Command Handler

Often times the command handler functions are placed directly on the . When this approach is taken, simply registering the Aggregate as described above is sufficient for all its command handler methods to be registered too.

however do require direct registration as being a command handler, which is shown in the following sample:

Given the existence of the following Command Handler:

public class GiftCardCommandHandler {

    private final Repository<GiftCard> giftCardRepository;

    @CommandHandler
    public void handle(RedeemCardCommand cmd) {
        giftCardRepository.load(cmd.getCardId())
                          .execute(giftCard -> giftCard.handle(cmd));
    }
    // omitted constructor
}

The following is needed to register a GiftCardCommandHandler as being a Command Handler:

Configurer axonConfigurer = DefaultConfigurer.defaultConfiguration()
    .registerCommandHandler(conf -> new GiftCardCommandHandler());

Or, a more general approach to registering all types of message handlers in a component can be used:

Configurer axonConfigurer = DefaultConfigurer.defaultConfiguration()
    .registerMessageHandler(conf -> new GiftCardCommandHandler());

When using Spring Boot, simply specifying the Command Handler as a bean is sufficient:

@Component
public class GiftCardCommandHandler {

    private final Repository<GiftCard> giftCardRepository;

    @CommandHandler
    public void handle(RedeemCardCommand cmd) {
        giftCardRepository.load(cmd.getCardId())
                          .execute(giftCard -> giftCard.handle(cmd));
    }
    // omitted constructor
}

Duplicate Command Handling Functions

Command Model Repositories

The repository is the mechanism that provides access to aggregates. The repository acts as a gateway to the actual storage mechanism used to persist the data. In CQRS, repositories only need to be able to find aggregates based on their unique identifier. Any other types of queries should be performed against the query database.

Note that the Repository interface does not prescribe a delete(identifier) method. Deleting aggregates is done by invoking the AggregateLifecycle.markDeleted() method from within an aggregate. Deleting an aggregate is a state migration like any other, with the only difference that it is irreversible in many cases. You should create your own meaningful method on your aggregate which sets the aggregate's state to "deleted". This also allows you to register any events that you would like to have published.

Configurer configurer = DefaultConfigurer.defaultConfiguration()
        .configureAggregate(
            AggregateConfigurer.defaultConfiguration(GiftCard.class)
                .configureRepository(c -> EventSourcingRepository.builder(GiftCard.class)
                .eventStore(c.eventStore())
                .build())
        );

To fully customize the repository used, you can define one in the application context. For Axon Framework to use this repository for the intended aggregate, define the bean name of the repository in the repository attribute on @Aggregate Annotation. Alternatively, specify the bean name of the repository to be the aggregate's name, (first character lowercase), suffixed with Repository. So on a class of type GiftCard, the default repository name is giftCardRepository. If no bean with that name is found, Axon will define an EventSourcingRepository (which fails if no EventStore is available).

@Bean
public Repository<GiftCard> repositoryForGiftCard(EventStore eventStore) {
    return EventSourcingRepository.builder(GiftCard.class).eventStore(eventStore).build();
}

@Aggregate(repository = "repositoryForGiftCard")
public class GiftCard { /*...*/ }

Note that this requires full configuration of the Repository, including any SnapshotTriggerDefinition or AggregateFactory that may otherwise have been configured automatically.

Standard Repositories

Standard repositories store the actual state of an aggregate. Upon each change, the new state will overwrite the old. This makes it possible for the query components of the application to use the same information the command component also uses. This could, depending on the type of application you are creating, be the simplest solution. If that is the case, Axon provides some building blocks that help you implement such a repository.

Axon provides one out-of-the-box implementation for a standard Repository: the GenericJpaRepository. It expects the Aggregate to be a valid JPA Entity. It is configured with an EntityManagerProvider which provides the EntityManager to manage the actual persistence, and a class specifying the actual type of aggregate stored in the repository. You also pass in the EventBus to which events are to be published when the aggregate invokes the static AggregateLifecycle.apply() method.

You can also easily implement your own repository. In that case, it is best to extend from the abstract LockingRepository. As aggregate wrapper type, it is recommended to use the AnnotatedAggregate. See the sources of GenericJpaRepository for an example.

Event Sourcing Repositories

Aggregate roots that are able to reconstruct their state based on events may also be configured to be loaded by an event sourcing repository. Those repositories do not store the aggregate itself, but the series of events generated by the aggregate. Based on these events, the state of an aggregate can be restored at any time.

Aggregate Factories

Optionally, you can provide an aggregate factory. The AggregateFactory specifies how an aggregate instance is created. Once an aggregate has been created, the EventSourcingRepository can initialize it using the events it loaded from the event store. Axon Framework comes with a number of AggregateFactory implementations that you may use. If they do not suffice, it is very easy to create your own implementation.

GenericAggregateFactory

The GenericAggregateFactory is a special AggregateFactory implementation that can be used for any type of event sourced aggregate root. The GenericAggregateFactory creates an instance of the aggregate type the repository manages. The aggregate class must be non-abstract and declare a default no-arg constructor that does no initialization at all.

The GenericAggregateFactory is suitable for most scenarios where aggregates do not need special injection of non-serializable resources.

SpringPrototypeAggregateFactory

Depending on your architectural choices, it might be useful to inject dependencies into your aggregates using Spring. You could, for example, inject query repositories into your aggregate to ensure the existence (or nonexistence) of certain values.

To inject dependencies into your aggregates, you need to configure a prototype bean of your aggregate root in the Spring context that also defines the SpringPrototypeAggregateFactory. Instead of creating regular instances of using a constructor, it uses the Spring Application Context to instantiate your aggregates. This will also inject any dependencies in your aggregate.

Implementing your own Aggregate Factory

In some cases, the GenericAggregateFactory just doesn't deliver what you need. For example, you could have an abstract aggregate type with multiple implementations for different scenarios (e.g. PublicUserAccount and BackOfficeAccount both extending an Account). Instead of creating different repositories for each of the aggregates, you could use a single repository, and configure an AggregateFactory that is aware of the different implementations.

The bulk of the work the aggregate factory does is creating uninitialized aggregate instances. It must do so using a given aggregate identifier and the first event from the stream. Usually, this event is a creation event which contains hints about the expected type of aggregate. You can use this information to choose an implementation and invoke its constructor. Make sure no events are applied by that constructor; the aggregate must be uninitialized.

Initializing aggregates based on the events can be a time-consuming effort, compared to the direct aggregate loading of the simple repository implementations. The CachingEventSourcingRepository provides a cache from which aggregates can be loaded if available.

As specified in the section, a command always has exactly one destination. That means there should only be a single Command Handler method for any given command.

By default, when a duplicate Command Handler method is registered, the last registration will be kept and a warning is logged. This behaviour can be adjusted by specifying a different DuplicateCommandHandlerResolver, as is described in the section.

In Axon Framework, all repositories must implement the Repository interface. This interface prescribes three methods: load(identifier, version), load(identifier) and newInstance(factoryMethod). The load methods allows you to load aggregates from the repository. The optional version parameter is used to detect concurrent modifications (see ). newInstance is used to register newly created aggregates in the repository.

Depending on your underlying persistence storage and auditing needs, there are a number of base implementations that provide basic functionality needed by most repositories. Axon Framework makes a distinction between repositories that save the current state of the aggregate (see ), and those that store the events of an aggregate (see ).

The EventSourcingRepository implementation provides the basic functionality needed by any event sourcing repository in the Axon Framework. It depends on an EventStore (see ), which abstracts the actual storage mechanism for the events.

Messaging Concepts
Runtime Tuning
Conflict resolution
Event store implementations
Standard repositories
Event Sourcing repositories
Aggregates
aggregate
External Command Handlers