Axon @QueryHandler 与 Spring @ExceptionHandler

Axon @QueryHandler with Spring @ExceptionHandler

在使用 Axon @QueryHandler 中抛出的异常时遇到问题,该异常被注释为 Spring @ResponseStatus。原始异常被 QueryHandler 吞没,Axon 特定的 AxonServerRemoteQueryHandlingException 被抛出,当 spring 响应客户端

时实际给出 500

仍然可以从 Axon 异常中获取一些信息,例如原始 "Entity not found" 消息,但不是异常类型,也不是原始异常包含的任何其他信息。

Q1:有什么方法可以将查询处理程序中抛出的异常提升到 Spring 响应中作为 404

Spring 异常处理程序

@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class NotFoundException extends ServiceException() {
  ...
}

Axon 查询处理程序

@QueryHandler
public Application getApplicationById(ApplicationByIdQuery query) {
  return applicationRepository.findById(query.getId())
      .orElseThrow(() -> new NotFoundException(Application.class, query.getId()));
}

Spring 控制器

@Autowired
QueryGateway queryGateway;

@GetMapping(path = "/{applicationId}")
public CompletableFuture<Application> getApplication(@PathVariable String applicationId) {
  return queryGateway.query(new ApplicationByIdQuery(applicationId), ResponseTypes.instanceOf(Application.class));
}

实际结果json:

{
  "timestamp": "2019-02-08T08:04:03.629+0000",
  "status": 500,
  "error": "Internal Server Error",
  "message": "An exception was thrown by the remote message handling component.",
  "path": "/api/applications/dff59c46-baf1-40f5-8a21-9286d1f8e36fx"
}

Q2:我的另一个问题是为什么不直接使用常规 JPA 查询 API 而是使用 Axon 的 QueryHandler。投影表是常规的 JPA 表,可以通过非常强大的 Spring JPA 进行查询。是因为直接查询不能保证投影数据的一致性吗?我经历了很多例子,其中大部分使用直接访问(见下文),其余的不解决底层 QueryHandler

抛出的异常
@Autowired
ApplicationRepository applicationRepository;

public CompletableFuture<Application> getApplication(@PathVariable String applicationId) {
  return CompletableFuture.supplyAsync(() -> applicationRepository.findById(applicationId)
                .orElseThrow(() -> new NotFoundException(Application.class, applicationId)));   
}

希望我能在这space中给你一些建议。

问题 1 的答案:

Axon 服务器总是将命令、事件或查询 dispatching/handling 异常包装到其他内容中。

因此,如果您想有条件地对远程查询处理异常做出反应,我认为您必须在代码中添加一个 @ExceptionHandler(AxonServerRemoteQueryHandlingException.class) 注释函数。 AxonServerRemoteQueryHandlingException 包含有关其包装的异常的更多信息,从而为您提供一个句柄以在必要时发送特定响应。

然而,包装异常的格式目前并不理想。从 Axon Framework/Server 4.1 开始,计划也在异常中包含 类。这将使您在处理异常时更容易、更细粒度地控制。

问题2的答案:

使用专用查询消息和查询处理程序背后的想法是,您可以将对某些数据感兴趣的一方与您实现提供答案的方式分离。

在框架中有专门的 QueryBus@QueryHandler 解决方案之前,您的建议是您唯一的选择。 然而,为此使用专用查询消息的概念允许您拥有一个完全独立的(微)服务来回答您的查询,而无需查询发送者知道该服务所在的位置。

在 Axon 应用程序中利用查询和查询处理程序是为您提供“Location Transparency”的支柱之一。你完全可以不使用框架提供的查询逻辑,但我个人认为它是进化微服务的一个很好的推动者。

希望这对您有所帮助,汤姆!