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 提供支持
在本页
  • Writing a Query Handler
  • Query Handler Call Order
  • Query Handler Return Values
  • Supported Single Instance Return Values
  • Supported Multiple Instances Return Values
  • Unsupported Return Values
  1. Axon Framework
  2. 查询

查询处理程序

Query Handlers

上一页查询调度器下一页实现

最后更新于2年前

The handling of a query comes down to an annotated handler returning the query's response. The goal of this chapter is to describe what such an @QueryHandler annotated method looks like, as well as describing the call order and response type options. For configuration of query handlers and the QueryBus, it is recommended to read the section.

Writing a Query Handler

In Axon, an object may declare a number of query handler methods, by annotating them with the @QueryHandler annotation. The object in question is what you would refer to as the Query Handler, or Query Handling Component. For a query handler method, the first declared parameter defines which query message object it will receive.

Taking the 'Gift Card' domain which contains a CardSummary Query Model, we can assume there is a query message to fetch a single CardSummary instance. Let us define the format of the query message as follows:

public class FetchCardSummaryQuery {

    private final String cardSummaryId;

    public FetchCardSummaryQuery(String cardSummaryId) {
        this.cardSummaryId = cardSummaryId;
    }
    // omitted getters, equals/hashCode, toString functions
}

As shown, we have a regular POJO that will fetch a CardSummary based on the cardSummaryId field. This FetchCardSummaryQuery will be to a handler that defines the given message as its first declared parameter. The handler will likely be contained in an object which is in charge of or has access to the CardSummary model in question:

import org.axonframework.queryhandling.QueryHandler;

public class CardSummaryProjection {

    private Map<String, CardSummary> cardSummaryStorage;

    @QueryHandler // 1.
    public CardSummary handle(FetchCardSummaryQuery query) { // 2.
        return cardSummaryStorage.get(query.getCardSummaryId());
    }
    // omitted CardSummary event handlers which update the model
}

From the above sample we want to highlight two specifics when it comes to writing a query handler:

  1. The @QueryHandler annotation which marks a function as a query handler method.

  2. The method in question is defined by the return type CardSummary, which is called the query response type, and the FetchCardSummaryQuery which is the query payload.

Storing a Query Model

For the purpose of the example we have chosen to use a regular Map as the storage approach. In a real life system, this would be replaced by a form of database or repository layer for example.

Query Handler Call Order

In all circumstances, at most one query handler method is invoked per query handling instance. Axon will search for the most specific method to invoke, using following rules:

  1. On the actual instance level of the class hierarchy (as returned by this.getClass()), all annotated methods are evaluated

  2. If one or more methods are found of which all parameters can be resolved to a value, the method with the most specific type is chosen and invoked

  3. If no methods are found on this level of the class hierarchy, the super type is evaluated the same way

  4. When the top level of the hierarchy is reached, and no suitable query handler is found, this query handling instance is ignored.

Note that similar to command handling, and unlike event handling, query handling does not take the class hierarchy of the query message into account.

// assume QueryB extends QueryA 
// and    QueryC extends QueryB
// and    a single instance of SubHandler is registered

public class QueryHandler {

    @QueryHandler
    public MyResult handle(QueryA query) {
        // Return result
    }

    @QueryHandler
    public MyResult handle(QueryB query) {
        // Return result
    }

    @QueryHandler
    public MyResult handle(QueryC query) {
        // Return result

    }
}

public class SubQueryHandler extends QueryHandler {

    @QueryHandler
    public MyResult handleEx(QueryB query) {
        // Return result
    }
}

In the example above, the handler method of SubQueryHandler will be invoked for queries for QueryB and result MyResult the handler methods of QueryHandler are invoked for queries for QueryA and QueryC and result MyResult.

Query Handler Return Values

Supported Single Instance Return Values

To query for a single object, the ReponseTypes#instanceOf(Class) method should be used to create the required ResponseType object. This "instance-of-Class" ResponseType object in turn supports the following query handler return values:

  • An exact match of Class

  • A subtype of Class

  • A generic bound to Class

  • A Future of Class

  • A primitive of Class

  • An Optional of Class

Primitive Return Types

Among the usual Objects, it is also possible for queries to return primitive data types:

public class QueryHandler {
 
     @QueryHandler
     public float handle(QueryA query) {
     }
 }

Note that the querying party will retrieve a boxed result instead of the primitive type.

Supported Multiple Instances Return Values

To query for a multiple objects, the ReponseTypes#multipleInstancesOf(Class) method should be used to create the required ResponseType object. This "multiple-instances-of-Class" ResponseType object in turn supports the following query handler return values:

  • An array containing:

    • Class

    • A subtype of Class

    • A generic bound to Class

  • An Iterable or a custom implementation of Iterable containing:

    • Class

    • A subtype Class

    • A generic bound to Class

    • A wildcard bound to Class

  • A Stream of Class

  • A Future of an Iterable of Class

Unsupported Return Values

The following list contains method return values which are not supported when queried for:

  • An array of primitive types

  • A Map of a given key and value type

Axon allows a multitude of return types for a query handler method, as defined on this page. You should think of single objects and collections of objects, taking into account wildcards or generics too. Below we share a list of all the options which are supported and tested in the framework.

For clarity we make a deviation between single instance and multiple instances of a response type. This follows the requirement to specify the ResponseType when , which expects the user to state if either a single result or multiple results are desired. Axon will use this ResponseType object to match a query with a query handler method, along side the query payload and query name.

Configuration
dispatched
dispatching a query
earlier