【问题标题】:In Java Spring Integration, can a transformer element include router functionality?在 Java Spring Integration 中,transformer 元素可以包含路由器功能吗?
【发布时间】:2015-10-15 21:18:41
【问题描述】:

我需要一个组件:

  1. 接收消息,对消息的有效负载和标头进行转换(到目前为止,它的作用类似于转换器)。

  2. 然后,根据在标头中传递的值路由到适当的通道(类似于标头路由器)。

我想纯粹使用 java 中的注释而不是 XML 来配置它,但我绝对会在这方面采取我能得到的东西。如果有人知道 XML 解决方案,请传递它。

如果有帮助,我的用例是我希望转换器对消息负载执行的转换依赖于自定义加载的标头值。我还希望用于从转换器发送消息的通道依赖于标头值。

我知道涉及多个转换器的解决方案,每个转换类型在标头值中定义一个,然后是一个路由器。我试图避免这种解决方案,最多只使用一个路由器和一个变压器。

感谢您的帮助。

【问题讨论】:

    标签: java spring spring-integration spring-annotations


    【解决方案1】:

    在 Spring Integration 中,通道充当任何其他 bean。您可以使用服务激活器来调用任何 bean 上的方法。该 bean 可以注入所需的通道。您可以使用@Qualifier 注释来选择应该注入哪个通道,或者只是自动装配一个Map<String, MessageChannel>,它将由通道的bean 名称索引。它可以将转换后的消息传递到这些通道。

    一个 Spring Boot 应用程序:

    package demo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.ImportResource;
    import org.springframework.integration.config.EnableIntegration;
    
    @SpringBootApplication
    @EnableIntegration
    @ImportResource("classpath:int.xml")
    public class DemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    
    
    }
    

    网关接口:

    package demo;
    
    public interface MyGateway {
        public void send(Object o);
    }
    

    要调用的服务:

    package demo;
    
    import java.util.Map;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.integration.support.MessageBuilder;
    import org.springframework.messaging.Message;
    import org.springframework.messaging.MessageChannel;
    import org.springframework.stereotype.Service;
    
    @Service
    public class MyService {
    
        private final Map<String, MessageChannel> channels;
    
        @Autowired
        public MyService(Map<String, MessageChannel> channels) {
            super();
            this.channels = channels;
        }
    
        public void transformAndRoute(Message<?> in) {
            // do your business logic here
            Message<?> out = MessageBuilder.fromMessage(in).build();
    
            // if(something)...
            channels.get("fooChannel").send(out);
        }
    
    }
    

    集成配置:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:int="http://www.springframework.org/schema/integration"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/integration
        http://www.springframework.org/schema/integration/spring-integration.xsd">
    
        <int:gateway id="myGateway" service-interface="demo.MyGateway"
            default-request-channel="inChannel" />
    
        <int:service-activator input-channel="inChannel"
            ref="myService" method="transformAndRoute" />
    
        <int:channel id="inChannel" />
    
    
        <int:logging-channel-adapter id="fooChannel" level="INFO" log-full-message="true"/>
    
    </beans>
    

    最后是一个简单的集成测试:

    package demo;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes=DemoApplication.class)
    public class MyGatewayIT {
    
        @Autowired
        MyGateway myGateway;
    
        @Test
        public void test() {
            myGateway.send(new Object());
    
            // do your assertions here
        }
    
    }
    

    输出:

    14:17:19.733 [main] DEBUG o.s.i.handler.LoggingHandler - org.springframework.integration.handler.LoggingHandler#0 received message: GenericMessage [payload=java.lang.Object@6f2cfcc2, headers={id=6791344c-07b4-d420-0d17-e2344f4bf15b, timestamp=1437826639733}]
    

    但是

    开发基于消息的系统的主要好处是您可以使用易于测试、重用和更改的小型松散耦合组件创建应用程序。创建一个在流程中扮演两个角色的组件会破坏该规则。此外,如果您按上述方式创建代码,则您的代码确实与 Spring Integration 相关联。相反,您可以做的是创建几个组件,每个组件都有一个单一的职责,然后将它们配置为链式运行。

    您可以做的是创建一个转换器来修改消息的有效负载和标头。该转换器将封装您的业务逻辑并设置一个标头(例如,myRoutingHeader),以后可以在路由中使用。拥有一个用于业务逻辑的转换器和一个用于添加标头的标头丰富器可能会更好。但是让我们假设你在一个班级里做这件事。将该类定义为 bean(比如myTransformer)。然后在你的配置中:

    <int:channel id="inChannel/>
    
    <!-- if performance is important consider using a SpEL expression to 
        invoke your method instead as they can be configured to be compiled -->
    <int:transformer ref="myTransformer" input-channel="inChannel"
                 method="transform" output-channel="routingChannel"/>
    
    <int:channel id="routingChannel/>
    
    <int:header-value-router input-channel="routingChannel" header-name="myRoutingHeader">
        <int:mapping value="foo" channel="fooChannel" />
        <int:mapping value="bar" channel="barChannel" />
    </int:header-value-router>
    

    【讨论】:

    • 谢谢您,先生,您在“BUT”之后的解决方案非常适合我的需求。这也是我的意思而不是我实际提出的问题的答案。
    【解决方案2】:

    听起来像链接会为你做这件事

    <chain input-chanel="source" output-channel="routing-channel">
     <transform/>
     <!-- any enrichment process or intermediate process can go here -->
    </chain>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-23
      相关资源
      最近更新 更多