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)
。您可能已经注意到,它没有使用 any 的 InjectionPoint
.
概念
我相信实施这个并不难。快速浏览一下 AutowireCapableBeanFactory#resolveDependency(DependencyDescriptor, String)
方法就足够了(DependencyDescriptor
是 InjectionPoint
的实现)。可能值得为此在 Axon 的 GitHub 上提供一个问题,甚至更好,一个 PR。
建议
但是,我还有另一个建议,即在不将其注入 every 消息处理函数的情况下实现相同的非功能性日志记录要求。
要在 Axon 应用程序中实现这种形式的日志记录,您可以采用两种方式:
- 使用
MessageHandlerInterceptor
s 和 MessageDispatchInterceptor
s 记录任何消息的摄取和处理。快速解决方案是为此使用 Axon 的 LoggingInterceptor
,它实现了两个接口。从那里,您可以将它注册到每个消息调度和处理组件(因此 CommandBus
、EventBus
、所有 EventProcessor
和 QueryBus
)。
- 提供一个
HandlerEnhancerDefintion
,它将 every 消息处理函数与您的日志记录逻辑包装在一起。为此提供一个 Bean 应该足以让 Axon 拾取它并自动包装所有 @MessageHandler
注释方法。
执行其中任何一个都意味着您不会阻碍处理命令、事件和查询的逻辑,而日志记录的逻辑相当枯燥。
这是我的两分钱,希望对安德烈有所帮助!
我正在编写我的第一个 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)
。您可能已经注意到,它没有使用 any 的 InjectionPoint
.
我相信实施这个并不难。快速浏览一下 AutowireCapableBeanFactory#resolveDependency(DependencyDescriptor, String)
方法就足够了(DependencyDescriptor
是 InjectionPoint
的实现)。可能值得为此在 Axon 的 GitHub 上提供一个问题,甚至更好,一个 PR。
建议
但是,我还有另一个建议,即在不将其注入 every 消息处理函数的情况下实现相同的非功能性日志记录要求。 要在 Axon 应用程序中实现这种形式的日志记录,您可以采用两种方式:
- 使用
MessageHandlerInterceptor
s 和MessageDispatchInterceptor
s 记录任何消息的摄取和处理。快速解决方案是为此使用 Axon 的LoggingInterceptor
,它实现了两个接口。从那里,您可以将它注册到每个消息调度和处理组件(因此CommandBus
、EventBus
、所有EventProcessor
和QueryBus
)。 - 提供一个
HandlerEnhancerDefintion
,它将 every 消息处理函数与您的日志记录逻辑包装在一起。为此提供一个 Bean 应该足以让 Axon 拾取它并自动包装所有@MessageHandler
注释方法。
执行其中任何一个都意味着您不会阻碍处理命令、事件和查询的逻辑,而日志记录的逻辑相当枯燥。
这是我的两分钱,希望对安德烈有所帮助!