Spring集成 - 如何调试' Dispatcher没有订阅者'?

时间:2016-08-24 18:02:02

标签: java spring debugging spring-integration

我使用的是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);
    }
}

1 个答案:

答案 0 :(得分:1)

如果某些Dispatcher has no Subscribers没有活跃的SubscribableChannelSubscriber,那么我们会遇到MessageHandler错误。 “活动”表示根本没有定义或处于停止状态。

因此,对于application:test.fileReadingFlow.channel#1 MessageChannel的问题,我会再次查看fileReadingFlow IntegrationFlow并找到第二个匿名{{} 1}}。

我无法弄清楚调试此类问题的简单方法,因为有DirectChannel,但由于MessageChannel而无法跟踪。

所以,请显示Dispatcher has no Subscribers fileReadingFlow定义并让我们一起解决问题!

关注你的相关问题应该是这个问题:

IntegrationFlow

可能刚刚处于停止状态。

但是在实际代码之前我们无法确定。