当前位置: 首页 > 知识库问答 >
问题:

SpringBoot RabbitMQ-如何减少许多主题(事件)的样板?

洪飞驰
2023-03-14

我想知道在SpringBoot中初始化许多RabbitMQ队列/绑定时,是否有办法减少样板代码的数量?

遵循事件驱动的方法,我的应用程序产生了大约50种类型的事件(它将在稍后被分成几个较小的应用程序,但仍然)。每个事件都以类型"主题"去交换。某些事件被其他应用程序消耗,某些事件被发送它们的同一应用程序额外消耗。

让我们考虑一下出版和自我消费的情况。

在SpringBoot中,我需要为每个事件声明:

  1. 配置中的路由密钥名称(如“event.item.purchased”)

So-6以一种或另一种形式提及“购买物品”的地方。样板代码的数量简直快把我累死了:)如果有50个事件,那么很容易出错——添加新事件时,需要记住将其添加到6个位置。

理想情况下,对于每项活动,我希望:

  1. 在配置中指定路由键。队列名称可以通过附加公共前缀(特定于应用程序)来构建
  2. 使用一些注释或替代RabbitListener自动声明队列(通过路由键前缀),绑定到它,并侦听事件。

有办法优化吗?我考虑过自定义注释,但是RabbitListener不喜欢动态队列名称,如果我在某个util方法中声明队列和绑定,Spring引导就找不到它们的bean。也许有一种方法可以在代码中声明所有这些东西,但我相信这不是Spring的方法:)

共有1个答案

郭云
2023-03-14

所以我最终使用手动bean声明,并为每个bean使用1个bind()方法

@Configuration
@EnableConfigurationProperties(RabbitProperties::class)
class RabbitConfiguration(
    private val properties: RabbitProperties,
    private val connectionFactory: ConnectionFactory
) {

    @Bean
    fun admin() = RabbitAdmin(connectionFactory)

    @Bean
    fun exchange() = TopicExchange(properties.template.exchange)

    @Bean
    fun rabbitMessageConverter() = Jackson2JsonMessageConverter(
        jacksonObjectMapper()
            .registerModule(JavaTimeModule())
            .registerModule(Jdk8Module())
            .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
            .enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)
    )

    @Value("\${okko.rabbit.queue-prefix}")
    lateinit var queuePrefix: String

    fun <T> bind(routingKey: String, listener: (T) -> Mono<Void>): SimpleMessageListenerContainer {
        val queueName = "$queuePrefix.$routingKey"
        val queue = Queue(queueName)
        admin().declareQueue(queue)
        admin().declareBinding(BindingBuilder.bind(queue).to(exchange()).with(routingKey)!!)

        val container = SimpleMessageListenerContainer(connectionFactory)
        container.addQueueNames(queueName)
        container.setMessageListener(MessageListenerAdapter(MessageHandler(listener), rabbitMessageConverter()))
        return container
    }

    internal class MessageHandler<T>(private val listener: (T) -> Mono<Void>) {

        // NOTE: don't change name of this method, rabbit needs it
        fun handleMessage(message: T) {
            listener.invoke(message).subscribeOn(Schedulers.elastic()).subscribe()
        }
    }
}


@Service
@Configuration
class EventConsumerRabbit(
    private val config: RabbitConfiguration,
    private val routingKeys: RabbitEventRoutingKeyConfig
) {

    @Bean
    fun event1() = handle(routingKeys.event1)

    @Bean
    fun event2() = handle(routingKeys.event2)

    ...

    private fun<T> handle(routingKey: String): Mono<Void> = config.bind<T>(routingKey) {
        log.debug("consume rabbit event: $it")
        ... // handle event, return Mono<Void>
    }

    companion object {
        private val log by logger()
    }
}

@Configuration
@ConfigurationProperties("my.rabbit.routing-key.event")
class RabbitEventRoutingKeyConfig {
    lateinit var event1: String
    lateinit var event2: String
    ...
}
 类似资料:
  • 在我的应用程序中,我有几个模块不适合“is-a”或“has-a”关系,但仍然需要相互通信和传递数据。为了尝试松散地耦合这些模块,我实现了一个事件总线类,用于处理从“事件海报”到“事件侦听器”的消息传递。 如果类希望注册接收某些事件,它们可以实现< code>IEventListener。同样,如果需要将事件推到总线上,类可以调用< code > event bus::postEvent()。当调用

  • Redux 很大部分 受到 Flux 的启发,而最常见的关于 Flux 的抱怨是必须写一大堆的样板代码。在这章中,我们将考虑 Redux 如何根据个人风格,团队偏好,长期可维护性等自由决定代码的繁复程度。 Actions Actions 是用来描述在 app 中发生了什么的普通对象,并且是描述突变数据意图的唯一途径。很重要的一点是 不得不 dispatch 的 action 对象并非是一个样板代码

  • 当编写< code>redux-thunk函数(称为thunks)时,有许多样板文件可以很容易地提取出来。例如,在我们的大多数异步API调用中,我们执行以下操作,没有任何副作用: 轻松点。虽然这至少涵盖了我们70%的请求,但我确信有一种优雅的方式可以将上述代码抽象为类似这样的代码(伪代码): 当我们需要检查状态和其他副作用时,我们可以返回到适当的thunk。尽管在大多数情况下...我们可以把它砍掉

  • 创建一个有很多高质量图像的应用程序,我决定将图像缩小到所需的大小(这意味着如果图像比屏幕大,我会缩小它)。 我注意到,在一些设备上,如果图像被缩小,它们会变得模糊/像素化,但是在相同的设备上,对于相同的目标图像视图大小,如果图像没有缩小,它们看起来很好。 我决定进一步检查这个问题,并创建了一个小的POC应用程序来显示这个问题。 在向您展示代码之前,下面是我所说内容的演示: 很难看出区别,但是你可以

  • 问题内容: 每个想要使用java.util.logging的类通常都需要声明一个记录器,如下所示: 如何避免使用MyClass.class.getName()样板代码? 问题答案: 我在Eclipse中设置了一个模板,因此我只需要键入声明的一部分,然后Eclipse将为我自动完成其余部分。 因此,我只需要键入,hit ,后跟和,Eclipse将为我填写其余部分,并添加导入声明。 这不会减少样板代码

  • 问题内容: 让我们比较一下c:Hello_world.c: Hello_world.go: 都编译: 还有,这是什么? 大约1Mb的世界。你在跟我开玩笑吗?我做错了什么? (仅限Hello_go-> 893K) 问题答案: 文件较大是否有问题?我不知道Go,但是我认为它会静态链接某些运行时库,而C程序则不是这种情况。但是,只要程序变大,就不必担心。 如上所述这里,静态链接Go运行时是默认的。该页面