Spring Integration中按方法名与Bean名调用Channel为何结果不同?
咱们先把问题拆开来分析,核心原因其实是通道bean的名称定义和自动创建机制搞混了,导致三个订阅者实际上绑定到了两个完全不同的通道实例上:
1. 为什么调用publishAction时只有第三个订阅者响应?
你在定义PublishSubscribeChannel时用了@Bean(name = {"publishCha.input", "publishCha2.input"}),这里有个容易忽略的关键细节:当@Bean显式指定了name属性后,方法名publishAction就不再是这个bean的有效名称了——这个bean的唯一注册名称就是你指定的那两个别名:publishCha.input和publishCha2.input。
再看第三个订阅者的代码:
@Bean public IntegrationFlow anotherChannel() { return IntegrationFlows.from("publishAction") .handle(m -> System.out.println("ANOTHER CHANNEL IS HERE!")) .get(); }
这里的from("publishAction")会让Spring去查找名为publishAction的MessageChannel bean,但因为你没把这个名称注册给手动创建的PublishSubscribeChannel,Spring找不到对应的bean,就会自动创建一个新的默认通道(默认是DirectChannel类型),第三个订阅者实际上绑定的是这个自动生成的通道,而非你手动定义的PublishSubscribeChannel。
所以当你调用.channel("publishAction")发送消息时,消息只会发送到这个自动创建的通道,自然只有第三个订阅者能收到。
2. 为什么调用publishCha.input时只有前两个订阅者响应?
再看前两个订阅者的代码:
@Bean public IntegrationFlow publishCha() { return f -> f .handle(m -> System.out.println("In publishCha channel...")); }
当你定义一个没有指定from()的IntegrationFlow时,Spring Integration会自动为这个flow分配一个输入通道,名称规则是flowBeanName.input——也就是publishCha.input。而你正好把这个名称注册给了手动创建的PublishSubscribeChannel,所以这个flow会绑定到你定义的那个PublishSubscribeChannel实例上。同理,publishCha2这个flow也会绑定到同一个实例(因为publishCha2.input也是这个bean的别名)。
所以当你调用.channel("publishCha.input")发送消息时,消息会发送到你手动创建的PublishSubscribeChannel,自然只有前两个订阅者能收到,第三个订阅者绑定的是另一个完全独立的通道,根本收不到消息。
快速修复方案:让所有订阅者绑定到同一个通道
有两种简单的方式可以解决这个问题:
方式一:给手动创建的
PublishSubscribeChannel加上publishAction这个名称,修改@Bean注解:@Bean(name = {"publishAction", "publishCha.input", "publishCha2.input"}) public MessageChannel publishAction() { PublishSubscribeChannel ps = MessageChannels.publishSubscribe().get(); ps.setMaxSubscribers(8); return ps; }这样
publishAction就成为这个bean的名称之一,第三个订阅者的from("publishAction")就会绑定到你手动创建的通道上,不管调用哪个通道名称,所有订阅者都会收到消息。方式二:修改第三个订阅者的代码,让它绑定到正确的通道名称,比如:
@Bean public IntegrationFlow anotherChannel() { return IntegrationFlows.from("publishCha.input") .handle(m -> System.out.println("ANOTHER CHANNEL IS HERE!")) .get(); }这样三个订阅者都绑定到同一个
PublishSubscribeChannel实例,调用任意别名都会触发所有订阅者。
内容的提问来源于stack exchange,提问作者sarah

