【问题标题】:Translate JMS Queue XML config to Java config将 JMS 队列 XML 配置转换为 Java 配置
【发布时间】:2016-09-16 03:49:13
【问题描述】:

为了学习 Spring 集成,我一直在尝试创建一个简单、弹性的日志处理器。我也想坚持使用 java 配置方法。

我在翻译现有 XML 配置时遇到了困难,主要是因为我对 spring 太陌生了。

a question on the spring forumsGary Russell 中提出了一个类似的解决方案,使用发布-订阅 + JMS 模型和简单的 XML 配置。

我一直在尝试将他的建议转换为 Java 配置,但被卡住了。也就是说,我不确定用于出站通道适配器、服务激活器或如何正确设置消息顺序的正确实体。

这是 Gary 的 XML 配置:

   <int-file:inbound-channel-adapter id="dispatcher" 
        directory="spool" 
        channel="fileChannel">
        <int:poller fixed-delay="2000">
            <int:transactional/>
        </int:poller>
    </int-file:inbound-channel-adapter>

    <int:channel id="fileChannel" />

    <int-file:file-to-string-transformer input-channel="fileChannel" output-channel="dispatchChannel" />

    <int:publish-subscribe-channel id="dispatchChannel" />

    <int-jms:outbound-channel-adapter id="dispatcherJms" channel="dispatchChannel" order="1"
        connection-factory="connectionFactory"
        destination="dispatcher.queue" />

    <!-- If JMS Send was successful, remove the file (within the transaction)-->
    <int:service-activator input-channel="dispatchChannel" order="2" 
        output-channel="nullChannel" 
                    expression="headers.file_originalFile.delete()">

    <bean id="transactionManager" class="org.springframework.jms.connection.JmsTransactionManager">
        <property name="connectionFactory" ref="connectionFactory"/>
    </bean>

更新

根据下面的 cmets,我更新了 java 配置。

但是我仍然收到错误,很可能不了解实体之间的流程和连接,但原始问题已得到解答。

@Bean
@Transactional
@InboundChannelAdapter(channel = "dispatchChannel", poller = @Poller(fixedDelay = "2000"))
public MessageSource<?> dispatcher() {
    CompositeFileListFilter<File> filters = new CompositeFileListFilter<>();
    filters.addFilter(new SimplePatternFileListFilter(sourceFilenamePattern));
    //filters.addFilter(persistentFilter());

    FileReadingMessageSource source = new FileReadingMessageSource();
    source.setAutoCreateDirectory(true);
    source.setDirectory(new File(sourceDirectory));
    source.setFilter(filters);

    return source;
}

@Bean
public MessageChannel fileChannel() {
    return new DirectChannel();
}

@Bean
public PublishSubscribeChannel dispatchChannel() {
    return new PublishSubscribeChannel();
}

@Autowired
JmsTemplate jmsTemplate;

@Autowired
ConnectionFactory connectionFactory;

@Bean
@Order(1)
@ServiceActivator(inputChannel = "dispatchChannel")
public MessageHandler dispatcherJmsOutboundChannelAdapter(Message<File> message) {
    JmsSendingMessageHandler handler = new JmsSendingMessageHandler(jmsTemplate);
    handler.setDestinationName("dispatcher.queue");

    return handler;
}

@Bean
@Order(2)
@ServiceActivator(inputChannel = "dispatchChannel")
public void removeFile(Message<?> message) {
    //message.getHeaders().get(FileHeaders.ORIGINAL_FILE, File.class).delete();
    log.info("delete");
}

@Bean
public JmsTransactionManager transactionManager(ConnectionFactory connectionFactory) {
    return new JmsTransactionManager(connectionFactory);
}

我正在使用 spring boot 和几个启动组件,例如 activemq。我已经为 JmsListenerContainerFactory 和 @JmsListener 添加了 @Bean,尽管我不确定这些是否真的有必要。

在将@EnableJms 添加到我的配置文件以及@Autowiring jmstemplate 和connectionfactory 之前,我无法运行任何东西。

运行时,我现在收到的错误是:

    org.springframework.beans.factory.NoSuchBeanDefinitionException: 
    No qualifying bean of type [org.springframework.messaging.Message] found for dependency 
[org.springframework.messaging.Message<?>]: 
    expected at least 1 bean which qualifies as autowire candidate for this dependency. 
Dependency annotations: {}

【问题讨论】:

    标签: spring-integration


    【解决方案1】:

    这个

    <int:service-activator input-channel="dispatchChannel" order="2" 
        output-channel="nullChannel" 
                    expression="headers.file_originalFile.delete()">
    

    在 Java 中非常简单:

    @ServiceActivator(inputChannel = "dispatchChannel")
    public void removeFile(Message<?> message) {
        message.getHeaders().get(FileHeaders.ORIGINAL_FILE, File.class).delete();
    }
    

    <int-jms:outbound-channel-adapter>
    

    翻译成这样:

    @Bean
    @ServiceActivator(inputChannel = "dispatchChannel")
    public MessageHandler dispatcherJmsOutboundChannelAdapter() {
         JmsSendingMessageHandler handler = 
                     new JmsSendingMessageHandler(new JmsTemplate(this.connectionFactory));
         handler.setDestinationName("dispatcher.queue");
         return handler;
    }
    

    注意Reference Manual中的这一段。

    【讨论】:

    • 谢谢阿特姆。消息顺序是如何翻译的?也许我错过了。
    • M-m-m。如果我正确地按照您的要求,您可以在JmsSendingMessageHandler 上使用setOrder()
    • 再次感谢。在 Gary 的解决方案中,他有 order="1" 的 jms outbound-channel-adapter 和用于删除 order="2" 的文件的服务激活器
    • 好的。这就是我所说的setOrder()
    • 这提出了一个有趣的问题——我们不能将order 应用于POJO 样式的服务激活器(removeFile)——任何无序的处理程序都将在all之后运行> 有序处理程序。所以,如果我们想在 JMS 之前运行 POJO 处理程序,它是行不通的。一种解决方法是将@Bean 样式与ServiceActivatingHandler 一起使用( Orderable)。另一个是依赖申报顺序(我不喜欢)。
    【解决方案2】:

    最后一块拼图是 FileWritingMessageHandler

    @Bean
    public FileWritingMessageHandler fileWritingMessageHandler() {
        SpelExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression("headers.file_originalFile.delete()");
        FileWritingMessageHandler fileWritingMessageHandler = new FileWritingMessageHandler(expression);
        fileWritingMessageHandler.setOutputChannel(new NullChannel());
        fileWritingMessageHandler.setDeleteSourceFiles(true);
        return fileWritingMessageHandler;
    }
    

    【讨论】:

    • 请看我的回答。即使您的解决方案有效,我们必须用这样一个怪物来开销简单的文件删除操作也没关系:-)。
    • 感谢您提供更简单的解决方案。只是享受学习的过程,怪物会不时出现:)
    猜你喜欢
    • 2015-05-30
    • 2011-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-22
    • 2018-07-19
    • 2014-09-25
    • 2012-02-01
    相关资源
    最近更新 更多