我们正在使用Spring Cloud Stream作为我们基于微服务的体系结构中事件消息传递的基础实现。我们想更进一步,并在我们的服务和Spring Cloud Stream库之间提供一个抽象层,以允许动态频道订阅,而服务本身中没有太多样板配置代码。
最初的想法如下:
messaging-library
提供了一个BaseHandler
抽象类,所有单个服务都必须实现。特定服务的所有处理程序都希望使用相同的输入通道,尽管仅会调用与要处理的事件类型相对应的处理程序。如下所示:
public abstract class BaseEventHandler<T extends Event> {
@StreamListener
public abstract void handle(T event);
}
每个服务都提供自己的events
程序包,其中包含N
EventHandlers。有普通的POJO,必须以编程方式实例化。如下所示:
public class ServiceEventHandler extends BaseEventHandler<ImportantServiceEvent> {
@Override
public void handle(ImportantServiceEvent event) {
// todo stuff
}
}
请注意,这些是简单的类,目前还不是Spring bean,其中ImportantServiceEvent
实现了Event
。
我们的messaging-library
会在启动时尽早进行扫描,并执行处理程序初始化。为此,请完成以下步骤:
BaseEventHandler
的所有子类。@StreamListener
批注,并将其值更改为此服务的相应输入通道。由于我们的处理程序可能需要与某些其他应用程序组件(存储库等)进行对话,因此我们使用DefaultListableBeanFactory
将我们的处理程序实例化为单例,如下所示:
val bean = beanFactory.createBean(eventHandlerClass, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
beanFactory.registerSingleton(eventHandlerClass.getSimpleName(), bean);
此后,我们遇到了几个问题。
Spring Cloud Stream @StreamListener
注释是方法注释,因此无法继承。尽管如此,某种机制似乎仍能够在父级上找到它(因为StreamListenerAnnotationBeanPostProcessor
已注册)并尝试在ServiceEventHandler
初始化后执行后处理。我们的假设是Spring Cloud Stream使用类似AnnotationElementUtils.findAllMergedAnnotations()
的东西。
因此,我们认为可能能够在子类的每个实例化之前更改基类的注释值。因此,我们认为,尽管我们的BaseEventHandler
会简单地获得一个新值,然后在此初始化阶段结束时保持不变,但子类将在当时使用正确的通道名称实例化。实例化,因为我们不希望重新绑定。但是,事实并非如此,使用的@StreamListener
批注的值始终是基数。
然后的问题是:Spring Cloud Stream我们想要什么?还是我们这里遇到的一个普通的Java问题(似乎并非如此)? Spring Cloud Stream团队是否预见到了这样的用例,我们只是做错了吗?
这个问题也发布在Spring Cloud Stream tracker上,以防可能引起更多关注。
答案 0 :(得分:1)
由于同一个人监视SO和GitHub问题,因此在两个地方发布都毫无意义。对于问题,首选堆栈溢出。
您应该能够将BPP子类化;它特别具有以下扩展点:
/**
* Extension point, allowing subclasses to customize the {@link StreamListener}
* annotation detected by the postprocessor.
*
* @param originalAnnotation the original annotation
* @param annotatedMethod the method on which the annotation has been found
* @return the postprocessed {@link StreamListener} annotation
*/
protected StreamListener postProcessAnnotation(StreamListener originalAnnotation, Method annotatedMethod) {
return originalAnnotation;
}
然后用您的变量覆盖bean定义
@Bean(name = STREAM_LISTENER_ANNOTATION_BEAN_POST_PROCESSOR_NAME)
public static StreamListenerAnnotationBeanPostProcessor streamListenerAnnotationBeanPostProcessor() {
return new StreamListenerAnnotationBeanPostProcessor();
}