Spring integration 如何增加消息头

Spring integration 如何增加消息头,spring-integration,dsl,Spring Integration,Dsl,在SpringIntegrationJavaDSL中有没有办法修改现有的消息头 我正在使用SI Java DSL重新实现下载重试机制,并希望在出现故障时,在根据尝试次数(与限制相比)路由消息之前,增加包含下载尝试的消息头 基于SI中包含的RouterTests,我的路由工作得很好。使用HeaderRichers,我可以轻松添加标题,但我看不到修改现有标题的方法 谢谢 /** * Unit test of {@link RetryRouter}. * * Based on {@link R

在SpringIntegrationJavaDSL中有没有办法修改现有的消息头

我正在使用SI Java DSL重新实现下载重试机制,并希望在出现故障时,在根据尝试次数(与限制相比)路由消息之前,增加包含下载尝试的消息头

基于SI中包含的RouterTests,我的路由工作得很好。使用HeaderRichers,我可以轻松添加标题,但我看不到修改现有标题的方法

谢谢

/**
 * Unit test of {@link RetryRouter}.
 * 
 * Based on {@link RouterTests#testMethodInvokingRouter2()}.
 */
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
public class RetryRouterTests {

    /** Failed download attempts are sent to this channel to be routed by {@link ContextConfiguration#failedDownloadRouting( ) } */
    @Autowired
    @Qualifier("failed")
    private MessageChannel failed;

    /** Retry attempts for failed downloads are sent to this channel by {@link ContextConfiguration#failedDownloadRouting( ) }*/
    @Autowired
    @Qualifier("retry-channel")
    private PollableChannel retryChannel;

    /** Failed download attempts which will not be retried, are sent to this channel by {@link ContextConfiguration#failedDownloadRouting( ) }*/
    @Autowired
    @Qualifier("exhausted-channel")
    private PollableChannel exhaustedChannel;

    /**
     * Unit test of {@link ContextConfiguration#failedDownloadRouting( ) } and {@link RetryRouter}.
     */
    @Test
    public void retryRouting() {

        final int limit = 2;

        for ( int attempt = 0 ; attempt <= limit + 1 ; attempt++ ){

            this.failed.send( failed( attempt, limit) );

            if ( attempt < limit){

                assertEquals( payload( attempt ) , this.retryChannel.receive( ).getPayload( ) );
                assertNull(this.exhaustedChannel.receive( 0 ) );

            }else{

                assertEquals( payload( attempt ) , this.exhaustedChannel.receive( ).getPayload( ) );
                assertNotNull( this.exhaustedChannel.receive( ).getPayload( ) );
            }
        }

    }

    private Message<String> failed( int retry , int limit ) {

        return MessageBuilder
            .withPayload(  payload( retry ) )
            .setHeader("retries", new AtomicInteger( retry ) )
            .setHeader("limit", limit)
            .build();
    }

    private String payload (int retry){
        return "retry attempt "+retry;
    }


    @Configuration
    @EnableIntegration
    public static class ContextConfiguration {

        @Bean
        public MessageChannel loggerChannel() {
            return MessageChannels.direct().get();
        }

        @Bean(name = "retry-channel")
        public MessageChannel retryChannel() {
            return new QueueChannel();
        }

        @Bean(name = "exhausted-channel")
        public MessageChannel exhaustedChannel() {
            return new QueueChannel();
        }


        /**
         * Decides if a failed download attempt can be retried or not, based upon the number of attempts already made 
         * and the limit to the number of attempts that may be made. Logic is in {@link RetryRouter}.
         * <p>
         * The number of download attempts already made is provided as a header {@link #attempts} from the connector doing the download, 
         * and the limit to the number of attempts is another header {@link #retryLimit} which is originally setup as
         * a header by {@link DownloadDispatcher} from retry configuration.
         * <p>
         * Messages for failed download attempts are listened to on channel {@link #failed}. 
         * Retry attempts are routed to {@link #retryChannel()}
         *  
         * @return
         */
        @Bean
        public IntegrationFlow failedDownloadRouting() {

            return IntegrationFlows.from( "failed" )

                .handle( "headers.retries.getAndIncrement()" )
                .handle( logMessage ( "failed" ) )
                .route(new RetryRouter())
                .get();
        }

        /**
         * Decides if a failed download attempt can be retried or not, based upon the number of attempts already made 
         * and the limit to the number of attempts that may be made. 
         * <p>
         */
        private static class RetryRouter {

            @Router
            public String routeByHeader(@Header("retries") AtomicInteger attempts , @Header("limit") Integer limit) {

                if (attempts.intValue() < limit.intValue()){
                    return "retry-channel";
                }
                return "exhausted-channel";
            }

            /** This method is not used but is required by Spring Integration otherwise application context doesn't load because of
             * {@code Caused by: java.lang.IllegalArgumentException: Target object of type 
             * [class org.springframework.integration.dsl.test.routers.RetryRouterTests$RetryRouter] has no eligible methods for handling Messages.}
             * 
             * @throws UnsupportedOperationException if called
             */
            @SuppressWarnings("unused")
            public String routeMessage(Message<?> message) {

                throw new UnsupportedOperationException( "should not be used." );
            }
        }
    }
/**
*{@link RetryRouter}的单元测试。
* 
*基于{@link RouterTests#testMethodInvokingRouter2()}。
*/
@上下文配置
@RunWith(SpringJUnit4ClassRunner.class)
@肮脏的环境
公共类RetryRouterTests{
/**失败的下载尝试被发送到此通道,由{@link ContextConfiguration#failedDownloadRouting()}路由*/
@自动连线
@限定符(“失败”)
私有消息通道失败;
/**对失败下载的重试尝试通过{@link ContextConfiguration#failedDownloadRouting()}发送到此通道*/
@自动连线
@限定符(“重试通道”)
专用可轮询频道retryChannel;
/**失败的下载尝试将不会重试,通过{@link ContextConfiguration#failedDownloadRouting()}发送到此通道*/
@自动连线
@限定符(“耗尽通道”)
私人排污渠道;
/**
*{@link ContextConfiguration#failedDownloadRouting()}和{@link RetryRouter}的单元测试。
*/
@试验
公共void retryRouting(){
最终整数限值=2;

对于(int-trunt=0;trunt有一种方法可以在不修改标题的情况下完成所需的操作:

.enrichHeaders(h -> h.header("downloadRetries", new AtomicInteger()))
然后,当您需要增加它时,您应该执行以下操作:

.handle(m -> m.getHeaders().get("downloadRetries", AtomicInteger.class).getAndIncrement())
此句柄作为重试服务的发布订户通道上的第一个单向第一订户

更新

是单向“MessageHandler”,不适合配置“outputChannel”。这是集成流的结束

谢谢你分享关于这个问题的配置:现在我有一个问题,你理解错了。解决方案必须是这样的:

        return IntegrationFlows.from( "failed" )

            .publishSubscribeChannel(s -> s
                .subscribe(f -> f
                        .handle(m -> m.getHeaders().get("downloadRetries",
                                  AtomicInteger.class).getAndIncrement()))
            .handle( logMessage ( "failed" ) )
            .route(new RetryRouter())
            .get();
    }
如果我们有一个
PublishSubscribeChannel
,子流中的
.subscribe()
是第一个订阅者的第一个订阅者,而主流中的
.handle(logMessage(“failed”)
是第二个订阅者。在第一个订阅者完成工作之前不会调用最后一个订阅者


有关更多信息,请参阅Spring集成和。

以下代码确实有效

.handle( new GenericHandler<Message<String>>() {

    @Override
    public Object handle( Message<String> payload , Map<String,Object> headers ) {

        ((AtomicInteger)headers.get( "retries" )).getAndIncrement();
        return payload;
    }})
.handle(新的GenericHandler(){
@凌驾
公共对象句柄(消息负载、映射头){
((AtomicInteger)headers.get(“重试”)).getAndIncrement();
返回有效载荷;
}})

谢谢你的回答。我不确定限定符“发布订阅者频道上的第一个单向第一订阅者”的意义。我在测试代码中尝试了它,我已将其添加到原始问题中,但出现了一个错误,我无法取得任何进展,将添加到下一条评论中。原因:java.lang.IllegalArgumentException:在org.springframework.util.Assert.isNull(Assert.java:92)的org.springframework.integration.util.MessagingMethodInvokerHelper.findHandlerMethodsForTarget中找到方法匹配:[public byte[]…java.lang.String.valueOf(long)]的不明确参数类型[class java.lang.String](MessagingMethodInvokerHelper.java:497)抱歉,这是我的错误:
.handle()
不支持
表达式
变量。请参阅我答案中的更新。您应该提供
MessageHandler
实现以访问
消息头
。感谢您的帮助。它不运行:由以下原因引起:org.springframework.beans.factory.BeanCreationException:“currentComponent”(org.springframework.integration.dsl.test.routers.RetryRouterTests$ContextConfiguration$1@3b00856b)是单向“MessageHandler”,不适合配置“outputChannel”。这是集成流程的结束。请参阅我的答案的更新。