事件侦听器是对传入事件起作用的组件。 他们通常根据命令模型所做的决定来执行逻辑。 通常,这涉及更新视图模型或将更新转发到其他组件,例如与第三方集成的组件。 在某些情况下,事件处理程序会根据事件的(模式)自己抛出事件,或者甚至发送命令来触发
定义事件处理程序
在Axon中,一个对象可以用@EventHandler注释来声明一些EventHandler方法。该方法的声明参数定义了它将接收哪些事件。
Axon为以下参数类型提供开箱即用的支持:
- 第一个参数始终是事件消息的有效负载。在事件处理程序不需要访问消息的有效负载的情况下,您可以在@EventHandler注释中指定预期的有效负载类型。指定时,使用下面指定的规则解析第一个参数。如果您希望将有效内容作为参数传递,请不要在注释中配置有效内容类型。
- 使用@MetaDataValue注解的参数将使用注释中指示的键去解析元数据的值。如果该值不是必须的,required设置为false(默认),则在元数据值不存在时传递null。如果是必须的,则在元数据值不存在时解析器将不匹配,并防止调用该方法。
- MetaData类型的参数将注入一个EventMessage的整个MetaData。
- 用@Timestamp注解并且类型为java.time.Instant(或java.time.temporal.Temporal)将解析为EventMessage的时间戳。这个是事件产生的时间。
- 用@SequenceNumber注解并且类型为java.lang.Long或long的参数将解析为DomainEventMessage的sequenceNumber。这提供了事件产生的顺序(在它发起的聚合范围内)。
- Message类型的参数将接受整个EventMessage类型的数据传入, 如果第一个参数是消息类型的,如果没有指定泛型参数,那么它将匹配任何类型的事件, 由于类型擦除,在Axon无法检测到预期的载荷类型时,最好在Message的泛型参数中声明有效载荷类型。
当使用Spring并且激活AxonConfiguration时(通过包含Axon Spring Boot Starter模块或者在@Configuration类中使用@EnableAxon注解),则任何其他参数都将解析为依赖注入的Bean。 这使您可以将资源直接注入到@EventHandler注解的方法中。
您可以通过实现ParameterResolverFactory接口并创建一个名为/META-INF/service/org.axonframework.common.annotation.ParameterResolverFactory的文件来配置其他ParameterResolver,该文件包含实现类的完全限定名。 详情请参阅高级自定义设置。
在任何情况下,每个侦听器实例最多调用一个事件处理方法。 Axon将使用以下规则搜索最具体的事件处理方法:
- 在由this.getClass()返回类中,搜索所有注释了@EventHandler的方法
- 如果找到一个或多个方法可以将所有参数解析为值,则选择并调用传入的数据类型和方法的参数类型最匹配的方法
- 如果在该层次的层次结构中找不到方法,则父类型中查找,方式相同
- 达到类层次结构的顶层时,找不到合适的事件处理程序时,该事件将被忽略。
//假设EventB extends EventA //并且EventC extends EventB //并且 SubListener 是单例 public class TopListener{ @EventHandler public void handle(EventA event){ } @EventHandler public void handle(EventC event){ } } public class SubListener extends TopListener{ @EventHandler public void handle(EventB event){ } }
在上面的例子中,SubListener的处理程序方法将针对EventB的所有实例以及EventC(因为它扩展了EventB)而被调用。 换句话说,TopListener的处理程序方法根本不会收到EventC的任何调用。 由于EventA不可分配给EventB(它是它的父类),因此事件将由TopListener中的处理程序方法处理。
注册事件处理程序
事件处理组件是使用EventHandlingConfiguration类定义的,该类被注册为全局Axon配置器的模块。 通常,应用程序将定义一个EventHandlingConfiguration,但更大的模块化应用程序可能会选择为每个模块定义一个。
要使用@EventHandler方法注册对象,请在EventHandlingConfiguration上使用registerEventHandler方法:
// define an EventHandlingConfiguration EventHandlingConfiguration ehConfiguration = new EventHandlingConfiguration().registerEventHandler(conf -> new MyEventHandlerClass()); // the module needs to be registered with the Axon Configuration Configurer axonConfigurer = DefaultConfigurer.defaultConfiguration().registerModule(ehConfiguration);
有关使用SpringAutoConfiguration注册事件处理程序的详细信息,请参阅事件处理配置章节。
查询处理
查询处理组件作用于传入的查询消息。 他们通常从Event监听器创建的视图模型中读取数据。 查询处理组件通常不会引发新事件或发送命令。
在Axon中,对象可以用@QueryHandler注解它们来声明多个QueryHandler方法。该方法的声明参数定义了它将接收哪些消息。
默认情况下,@QueryHandler注释的方法允许使用以下参数类型:
- 第一个参数是查询消息的有效负载。它可以是Message或QueryMessage类型,如果@QueryHandler注解没有显式定义查询的名称,默认情况下,查询名称是查询有效负载的完全限定类名称。
- 使用@MetaDataValue注解的参数将使用注解中指示的键解析元数据值。如果这个值是非必需的,required设为false(默认),则在元数据值不存在时会传递null。否则,元数据值不存在时解析器将不匹配,并防止在元数据值不存在时调用该方法。
- MetaData类型的参数将注入一个QueryMessage的整个MetaData。
- UnitOfWork类型的参数获取当前注入的工作单元。这允许查询处理程序注册要在工作单元的特定阶段执行的操作,或获取对其注册的资源的访问。
- 类型为Message或QueryMessage的参数将获得完整的消息,同时包含有效内容和元数据。如果一个方法需要几个元数据字段或消息封装的其他属性,这很有用。
您可以通过实现ParameterResolverFactory接口并创建一个名为/META-INF/service/org.axonframework.common.annotation.ParameterResolverFactory的文件来配置其他ParameterResolver,该文件包含实现类的完全限定名。 详情请参阅高级自定义设置章节。
在任何情况下,每个查询处理实例至多会调用一个查询处理程序方法。 Axon将使用以下规则查找最具体的调用方法:
- 在由this.getClass()返回的类中,查找所有注释的方法
- 如果找到一个或多个方法的所有参数可以匹配到值,则选择类型最匹配的方法
- 如果在该层次的层次结构中找不到方法,则在父类型中查找,匹配方式相同
- 达到类层次结构的顶层时,找不到合适的查询处理程序,此查询处理实例将被忽略。
请注意,与命令处理类似,与事件处理不同,查询处理不考虑查询消息的类层次结构。
//假设QueryB extends QueryA //并且QueryC extends QueryB //并且SubHandler是单例 public class TopHandler{ @QueryHandler public MyResulthandle(QueryA query){ } @QueryHandler public MyResulthandle(QueryB query){ } @QueryHandler public MyResulthandle(QueryC query){ } } public class SubHandler extends TopHandler{ @QueryHandler public MyResulthandleEx(QueryB query){ } }
在上面的例子中,将调用SubHandler的处理方法来查询QueryB和结果MyResult;对QueryA和QueryC的查询和结果MyResult调用TopHandler的处理程序方法。
注册查询处理程序
可以为相同的查询名称和响应类型注册多个查询处理程序。 当分派查询时,客户可以指示他是想要一个结果还是来自所有可用的查询处理程序。
使用Spring
当使用SpringAutoConfiguration时,所有singleton Spring bean都会被扫描以查找具有@QueryHandler批注的方法。 对于找到的每个方法,都会在查询总线中注册一个新的查询处理程序。
使用配置API
也可以使用配置API来注册查询处理程序。 为此,请在Configurer类上使用registerQueryHandler方法:
// Sample query handler public class MyQueryHandler{ @QueryHandler public Stringecho(String echo){ return echo; } } // To register yourquery handler Configurer axonConfigurer =DefaultConfigurer.defaultConfiguration().registerQueryHandler(conf-> new MyQueryHandler);