我使用的是Spring Boot 1.4.0.RELEASE,Spring Integration 4.3.1.RELEASE,Spring Integration DSL 1.2.0.M1。
我想做的事情:
我正在编写一个应用程序,它将从FTP和本地文件系统中读取文件(使用入站通道适配器),将文件传输到本地工作目录(使用文件出站网关),处理,然后将它们移动到最终目的地(文件出站网关/适配器)。
我遇到了问题' Dispatcher没有订阅频道'错误。我相信这可能意味着上下文中的某些内容被破坏而且Integration组件没有启动。上下文本身表示我在调试时它处于活动状态。
我的实际配置相当大,所以我没有找人为我找到解决方案。我正在寻找关于在哪里寻找以及如何弄清楚哪些组件在抱怨的指导。
实际错误如下。
DEBUG [integration.channel.ExecutorChannel] [task-scheduler-1] preSend on channel 'errorChannel', message: ErrorMessage [payload=org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'application:test.fileReadingFlow.channel#1'.
fileReadingFlow
是一个InboundChannelAdapter
,它从目录中读取文件(基本上,我询问的是here。它没有任何复杂的内容。适配器将消息发送给{ {1}}处理程序,丰富标题,将其发送到处理程序(.log()
),最后发送到Files.outboundgateway
。
我尝试过的事情:
MessageChannel
的链条和事物排队(没有拼写错误,所有MessageChannel
都存在)。Bean
中添加了更多LoggingHandler
来识别邮件错误的位置。fileReadingFlow
的部分内容,看看能不能再收到这条消息了。fileReadingFlow
以查看是否可以找到问题。Component
添加了调试日志记录,并且没有出现类似于错误或警告的内容。我发现第一次流尝试执行除日志记录以外的操作(甚至是enrichHeaders)时,发生了Dispatcher错误,并且消息最终出现在org.springframework.integration
中。当我将errorChannel
更改为仅读取文件,记录消息并以空处理程序终止时,我收到了Dispatcher错误。因此,我非常肯定问题不在于fileReadingFlow
本身。
除了逐个删除每个fileReadingFlow
之外,有没有办法找出导致错误的原因?
编辑:
来源:
Component
应用:
@Bean(name = "fileReadingFlow")
@Scope("prototype")
@Profile("test")
public IntegrationFlow testFileReadingFlow(MyEntity entity) {
return IntegrationFlows.from(s -> s.file(new File("someFolder")))
.filter(fileListFilterBuilder.buildFileListFilter(File.class))
, endpointConfigurer -> endpointConfigurer.poller(poller)
)
.log(DEBUG, "com.myco.testFileReadingFlow")
.enrichHeaders(h ->
h.header("entity", entity)
.header(FOLDER_NAME, entity.getFolder())
)
.log(DEBUG, "com.myco.testFileReadingFlow", message -> "after headers")
.handle(Files.outboundGateway("workingFolder").deleteSourceFiles(true).autoCreateDirectory(true))
.log(DEBUG, "com.myco.testFileReadingFLow", message -> "sending message to aggregatingFileChannel " + message)
.channel("aggregatingFileChannel")
.get();
}
@Bean
public MessageChannel aggregatingFileChannel() {
return MessageChannels.executor(Executors.newCachedThreadPool()).get();
}
@Bean
public IntegrationFlow aggregatingFlow() {
// Read from the aggregatingFileChannel
return from("aggregatingFileChannel")
<...>
.get();
}
解决方案:
根据我在下面的评论,@SpringBootApplication
@EnableConfigurationProperties
@EntityScan(
basePackages = { "com.myco.model" }
)
@EnableJpaRepositories(basePackages = {"com.myco.rest"})
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(Application.class).web(false).run(args);
MyEntitySvc entitySvc = context.getBean(MyEntitySvc.class);
List<MyEntity> entities = entitySvc.findAllActive();
AutowireCapableBeanFactory beanFactory = context.getBeanFactory();
entities.forEach(entity -> {
IntegrationFlow flow = (IntegrationFlow) context.getBean("fileReadingFlow", entity);
beanFactory.getBean(entity.getFolder() + MyConstants.ADAPTER, Lifecycle.class).start();
}
方法在某些时候确实有效,但我打破了它并且无法轻易地回滚更改。使用Gary和Artem的建议,我尝试改为使用@Prototype
方法。为了保留我最初的运行时启动,配置文件驱动注入等,我将IntegrationFlowContext
类的定义从IntegrationFlow
类移到了@Configuration
类。这样我就可以将@Service
注入IntegrationFlowContext
,并为我的不同配置文件实现Service
的不同版本,而无需Service
了解Application
}。主要方法是从Profile
中提取Bean
并手动启动它以检索Context
并调用方法。
Service
应用:
@Service
@Profile("test")
public class TestFlowSvc implements FlowSvc {
public IntegrationFlow testFileReadingFlow(Vendor vendor) {
return // As previous Flow
}
public void startFileReadingFlow(MyEntity entity) {
IntegrationFlow flow = testFileReadingFlow(entity);
integrationFlowContext.register(flow, true);
}
}
答案 0 :(得分:1)
如果某些Dispatcher has no Subscribers
没有活跃的SubscribableChannel
(Subscriber
,那么我们会遇到MessageHandler
错误。
“活动”表示根本没有定义或处于停止状态。
因此,对于application:test.fileReadingFlow.channel#1
MessageChannel
的问题,我会再次查看fileReadingFlow
IntegrationFlow
并找到第二个匿名{{} 1}}。
我无法弄清楚调试此类问题的简单方法,因为有DirectChannel
,但由于MessageChannel
而无法跟踪。
所以,请显示Dispatcher has no Subscribers
fileReadingFlow
定义并让我们一起解决问题!
关注你的相关问题应该是这个问题:
IntegrationFlow
可能刚刚处于停止状态。
但是在实际代码之前我们无法确定。