Axon Framework 不为 bean 工厂方法提供 InjectionPoint

Axon Framework does not provide InjectionPoint for bean factory methods

我正在编写我的第一个 Axon 教程,我想提供 Logger 作为 bean,这样我就可以轻松 mock/spy 它:

@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Logger logger(InjectionPoint ip) {
    return LoggerFactory.getLogger(ip.getMember().getDeclaringClass());
}

我通常像这样在构造函数中注入它:

@RestController
@RequiredArgsConstructor
class FoodOrderingController {

    private final Logger logger;
    private final CommandGateway commandGateway;
    private final QueryGateway queryGateway;

效果很好。但是,当我想将它注入聚合处理程序时,比如

@CommandHandler
public void handle(DeselectProductCommand command, Logger logger) throws ProductDeselectionException {

在这种情况下,我得到以下异常(没有堆栈跟踪):

2020-05-22 14:23:44.263  WARN 16680 --- [nio-8080-exec-7] o.a.c.gateway.DefaultCommandGateway      : Command 'com.example.axon.foodcart.coreapi.command.DeselectProductCommand' resulted in org.springframework.beans.factory.BeanCreationException(Error creating bean with name 'logger' defined in class path resource [com/example/axon/foodcart/CoreConfig.class]: Unexpected exception during bean creation; nested exception is java.lang.IllegalStateException: No current InjectionPoint available for method 'logger' parameter 0)

是否可以在 Axon Framework 中注入 Logger bean?还是我必须回到静态记录器?

回答

原因很可能是 SpringBeanParameterResolverFactory 及其 SpringBeanParameterResolver 用于检索 Spring bean 以注入消息处理函数的方式。

目前像您的 @CommandHandler public void handle(DeselectProductCommand ...) 这样的消息处理函数被调用。 SpringBeanParameterResolver#resolveParameterValue 方法将被调用,后者又调用 AutowireCapableBeanFactory#getBean(String)。您可能已经注意到,它没有使用 anyInjectionPoint.

概念

我相信实施这个并不难。快速浏览一下 AutowireCapableBeanFactory#resolveDependency(DependencyDescriptor, String) 方法就足够了(DependencyDescriptorInjectionPoint 的实现)。可能值得为此在 Axon 的 GitHub 上提供一个问题,甚至更好,一个 PR。


建议

但是,我还有另一个建议,即在不将其注入 every 消息处理函数的情况下实现相同的非功能性日志记录要求。 要在 Axon 应用程序中实现这种形式的日志记录,您可以采用两种方式:

  1. 使用 MessageHandlerInterceptors 和 MessageDispatchInterceptors 记录任何消息的摄取和处理。快速解决方案是为此使用 Axon 的 LoggingInterceptor,它实现了两个接口。从那里,您可以将它注册到每个消息调度和处理组件(因此 CommandBusEventBus、所有 EventProcessorQueryBus)。
  2. 提供一个 HandlerEnhancerDefintion,它将 every 消息处理函数与您的日志记录逻辑包装在一起。为此提供一个 Bean 应该足以让 Axon 拾取它并自动包装所有 @MessageHandler 注释方法。

执行其中任何一个都意味着您不会阻碍处理命令、事件和查询的逻辑,而日志记录的逻辑相当枯燥。


这是我的两分钱,希望对安德烈有所帮助!