【问题标题】:How to implement enricher using spring integraton java DSL?如何使用 spring 集成 java DSL 实现丰富器?
【发布时间】:2019-08-30 13:22:10
【问题描述】:

我想用 java DSL 重写following xml sample

xml 配置:

    <int:channel id="findUserServiceChannel"/>
    <int:channel id="findUserByUsernameServiceChannel"/>

    <!-- See also:
        https://docs.spring.io/spring-integration/reference/htmlsingle/#gateway-proxy
        https://www.enterpriseintegrationpatterns.com/MessagingGateway.html -->
    <int:gateway id="userGateway" default-request-timeout="5000"
                 default-reply-timeout="5000"
                 service-interface="org.springframework.integration.samples.enricher.service.UserService">
        <int:method name="findUser"                  request-channel="findUserEnricherChannel"/>
        <int:method name="findUserByUsername"        request-channel="findUserByUsernameEnricherChannel"/>
        <int:method name="findUserWithUsernameInMap" request-channel="findUserWithMapEnricherChannel"/>
    </int:gateway>

    <int:enricher id="findUserEnricher"
                  input-channel="findUserEnricherChannel"
                  request-channel="findUserServiceChannel">
        <int:property name="email"    expression="payload.email"/>
        <int:property name="password" expression="payload.password"/>
    </int:enricher>

    <int:enricher id="findUserByUsernameEnricher"
                  input-channel="findUserByUsernameEnricherChannel"
                  request-channel="findUserByUsernameServiceChannel"
                  request-payload-expression="payload.username">
        <int:property name="email"    expression="payload.email"/>
        <int:property name="password" expression="payload.password"/>
    </int:enricher>

    <int:enricher id="findUserWithMapEnricher"
                  input-channel="findUserWithMapEnricherChannel"
                  request-channel="findUserByUsernameServiceChannel"
                  request-payload-expression="payload.username">
        <int:property name="user"    expression="payload"/>
    </int:enricher>

    <int:service-activator id="findUserServiceActivator"
                           ref="systemService" method="findUser"
                           input-channel="findUserServiceChannel"/>

    <int:service-activator id="findUserByUsernameServiceActivator"
                           ref="systemService" method="findUserByUsername"
                           input-channel="findUserByUsernameServiceChannel"/>

    <bean id="systemService"
          class="org.springframework.integration.samples.enricher.service.impl.SystemService"/>

现在我有以下内容:

配置:

@Configuration
@EnableIntegration
@IntegrationComponentScan
public class Config {

    @Bean
    public SystemService systemService() {
        return new SystemService();
    }

    @Bean
    public IntegrationFlow findUserEnricherFlow(SystemService systemService) {
        return IntegrationFlows.from("findUserEnricherChannel")
                .<User>handle((p, h) -> systemService.findUser(p))
                .get();
    }

    @Bean
    public IntegrationFlow findUserByUsernameEnricherFlow(SystemService systemService) {
        return IntegrationFlows.from("findUserByUsernameEnricherChannel")
                .<User>handle((p, h) -> systemService.findUserByUsername(p.getUsername()))
                .get();
    }

    @Bean
    public IntegrationFlow findUserWithUsernameInMapFlow(SystemService systemService) {
        return IntegrationFlows.from("findUserWithMapEnricherChannel")
                .<Map<String, Object>>handle((p, h) -> {
                    User user = systemService.findUserByUsername((String) p.get("username"));
                    Map<String, Object> map = new HashMap<>();
                    map.put("username", user.getUsername());
                    map.put("email", user.getEmail());
                    map.put("password", user.getPassword());
                    return map;
                })
                .get();
}
}

服务接口:

@MessagingGateway
public interface UserService {

    /**
     * Retrieves a user based on the provided user. User object is routed to the
     * "findUserEnricherChannel" channel.
     */
    @Gateway(requestChannel = "findUserEnricherChannel")
    User findUser(User user);

    /**
     * Retrieves a user based on the provided user. User object is routed to the
     * "findUserByUsernameEnricherChannel" channel.
     */
    @Gateway(requestChannel = "findUserByUsernameEnricherChannel")
    User findUserByUsername(User user);

    /**
     * Retrieves a user based on the provided username that is provided as a Map
     * entry using the mapkey 'username'. Map object is routed to the
     * "findUserWithMapChannel" channel.
     */
    @Gateway(requestChannel = "findUserWithMapEnricherChannel")
    Map<String, Object> findUserWithUsernameInMap(Map<String, Object> userdata);

}

目标服务:

public class SystemService {

    public User findUser(User user) {
            ...
    }

    public User findUserByUsername(String username) {
            ...    
    }

}

主要方法:

public static void main(String[] args) {
    ConfigurableApplicationContext ctx = new SpringApplication(MyApplication.class).run(args);
    UserService userService = ctx.getBean(UserService.class);
    User user = new User("some_name", null, null);
    System.out.println("Main:" + userService.findUser(user));
    System.out.println("Main:" + userService.findUserByUsername(user));
    Map<String, Object> map = new HashMap<>();
    map.put("username", "vasya");
    System.out.println("Main:" + userService.findUserWithUsernameInMap(map));
}

输出:

2019-08-30 14:09:29.956  INFO 12392 --- [           main] enricher.MyApplication                   : Started MyApplication in 2.614 seconds (JVM running for 3.826)
2019-08-30 14:09:29.966  INFO 12392 --- [           main] enricher.SystemService                   : Calling method 'findUser' with parameter User{username='some_name', password='null', email='null'}
Main:User{username='some_name', password='secret', email='some_name@springintegration.org'}
2019-08-30 14:09:29.967  INFO 12392 --- [           main] enricher.SystemService                   : Calling method 'findUserByUsername' with parameter: some_name
Main:User{username='some_name', password='secret', email='some_name@springintegration.org'}
2019-08-30 14:09:29.967  INFO 12392 --- [           main] enricher.SystemService                   : Calling method 'findUserByUsername' with parameter: vasya
Main:{password=secret, email=vasya@springintegration.org, username=vasya}

如您所见,一切正常,但我在配置中进行了转换。我不确定我是否必须这样做,因为 xml 配置没有这样的转换,并且一切都使用内部魔法以某种方式工作。这是正确的方法还是我应该使用一些内部 DSL 魔法进行转换?

附言

我想Config 类可以以某种方式简化。我的意思是 findUserByUsernameEnricherFlow findUserWithUsernameInMapFlow 方法

更新

我意识到我并不真正了解 XML 配置的工作原理:

让我们考虑方法Userservice#findUserWithUsernameInMap方法

它有如下界面:

Map<String, Object> findUserWithUsernameInMap(Map<String, Object> userdata);

它最终会调用SystemServicefindUserByUsername方法:

public User findUserByUsername(String username) 

因为客户端代码使用Userservice,所以里面有2个转换:

  1. 在路上(在SystemService#findUserByUsername 调用之前)因为Userservice#findUserWithUsernameInMapaccept Map&lt;String, Object&gt;SystemService#findUserByUsername 接受字符串

  2. 返回途中(在SystemService#findUserByUsername 调用之后)因为SystemService#findUserByUsername返回用户但Userservice#findUserWithUsernameInMap 返回Map&lt;String, Object&gt;

这些转换究竟是在 xml 配置中的什么地方声明的?

我建议使用 request-payload-expression 来进行 TO 转换。看起来它可以使用与 Object 相同的方式与 Map 一起使用。但是 BACK 转换根本不清楚。当然配置有

<int:property name="user"    expression="payload"/>

但我不知道这是什么意思。

【问题讨论】:

  • 您是否介意将您的问题简化为您不喜欢的确切代码。现在自定义代码太多了,我相信可能与该主题无关。请尽可能清楚并尊重其他愿意帮助您的人的时间......
  • @Artem Bilan 对不起。我添加了有关可能简化的代码的信息。但我认为所有代码都与主题相关,无法删除

标签: java spring spring-integration spring-integration-dsl


【解决方案1】:

&lt;int:enricher&gt; 的 Java DSL 等效项是 .enrich()。所以,你的findUserEnricherFlow 应该是这样的:

@Bean
public IntegrationFlow findUserEnricherFlow(SystemService systemService) {
    return IntegrationFlows.from("findUserEnricherChannel")
            .enrich((enricher) -> enricher
                         .requestChannel("findUserServiceChannel")
                         .propertyExpression("email", "payload.email")
                         .propertyExpression("password", "payload.password"))

            .get();
}

您仍然可以简单地将您的问题仅指向一种网关方法和一种浓缩器...

【讨论】:

  • 在您的示例中会以某种方式调用 SystemService 吗?我调用 userService.findUser(user) 并且我希望 SI 将该请求分派到 theSystemService#findUser
  • SystemService 必须位于单独的IntegrationFlow 中,该IntegrationFlow 必须订阅该findUserServiceChannel 请求频道。在直接代码调用的情况下,Spring Integration 不会调度。这已经是您正确委派的serService.findUser(user) 代码责任。这里没有任何 Spring Integration 钩子。
  • 让我了解这里发生了什么。当我从主方法 SI routes 请求调用 userService.findUser(user) 到丰富器并基于有效负载(具有填充名称的用户对象)设置某些魔术实体的 2 个属性时.在它请求重定向到 SystemService 之后。所以我的问题是这里的浓缩器的ai是什么以及在浓缩器中填充了什么魔法实体
  • 我知道丰富器是 UserService 和 SystemService 之间的东西,但它的接口不同,所以我们必须在中间有一些适配器。看起来丰富器在这里是一个适配器,但我不明白它是如何在这里工作的
【解决方案2】:

最终我能够将 xml 重写为 java DSL。不幸的是,它有点冗长:

配置:

@Configuration
@EnableIntegration
@IntegrationComponentScan
public class Config {

    @Bean
    public SystemService systemService() {
        return new SystemService();
    }

    //first flow
    @Bean
    public IntegrationFlow findUserEnricherFlow() {
        return IntegrationFlows.from("findUserEnricherChannel")
                .enrich(enricherSpec ->
                        enricherSpec.requestChannel("findUserServiceChannel")
                                .<User>propertyFunction("email", (message) ->
                                        (message.getPayload()).getEmail()
                                ).<User>propertyFunction("password", (message) ->
                                (message.getPayload()).getPassword()
                        ))
                .get();
    }

    @Bean
    public IntegrationFlow findUserServiceFlow(SystemService systemService) {
        return IntegrationFlows.
                from("findUserServiceChannel")
                .<User>handle((p, h) -> systemService.findUser(p))
                .get();
    }

    //second flow
    @Bean
    public IntegrationFlow findUserByUsernameEnricherFlow() {
        return IntegrationFlows.from("findUserByUsernameEnricherChannel")
                .enrich(enricherSpec ->
                        enricherSpec.requestChannel("findUserByUsernameRequestChannel")
                                .<User>requestPayload(userMessage -> userMessage.getPayload().getUsername())
                                .<User>propertyFunction("email", (message) ->
                                        (message.getPayload()).getEmail()
                                ).<User>propertyFunction("password", (message) ->
                                (message.getPayload()).getPassword()
                        ))
                .get();

    }

    @Bean
    public IntegrationFlow findUserByUsernameServiceFlow(SystemService systemService) {
        return IntegrationFlows.from("findUserByUsernameRequestChannel")
                .<String>handle((p, h) -> systemService.findUserByUsername(p))
                .get();
    }

    //third flow
    @Bean
    public IntegrationFlow findUserWithUsernameInMapEnricherFlow() {
        return IntegrationFlows.from("findUserWithMapEnricherChannel")
                .enrich(enricherSpec ->
                        enricherSpec.requestChannel("findUserWithMapRequestChannel")
                                .<Map<String, User>>requestPayload(userMessage -> userMessage.getPayload().get("username"))
                                .<User>propertyFunction("user", Message::getPayload)
                ).get();
    }

    @Bean
    public IntegrationFlow findUserWithUsernameInMapServiceFlow(SystemService systemService) {
        return IntegrationFlows.from("findUserWithMapRequestChannel")
                .<String>handle((p, h) -> systemService.findUserByUsername(p))
                .get();
    }
}

另外我在UserService中加了一点注解:

@MessagingGateway
public interface UserService {

    /**
     * Retrieves a user based on the provided user. User object is routed to the
     * "findUserEnricherChannel" channel.
     */
    @Gateway(requestChannel = "findUserEnricherChannel")
    User findUser(User user);

    /**
     * Retrieves a user based on the provided user. User object is routed to the
     * "findUserByUsernameEnricherChannel" channel.
     */
    @Gateway(requestChannel = "findUserByUsernameEnricherChannel")
    User findUserByUsername(User user);

    /**
     * Retrieves a user based on the provided username that is provided as a Map
     * entry using the mapkey 'username'. Map object is routed to the
     * "findUserWithMapChannel" channel.
     */
    @Gateway(requestChannel = "findUserWithMapEnricherChannel")
    Map<String, Object> findUserWithUsernameInMap(Map<String, Object> userdata);

}

所有来源都可以在这里找到:https://github.com/gredwhite/spring-integration/tree/master/complete/src/main/java/enricher


我还发现:

@Bean
public IntegrationFlow findUserEnricherFlow(SystemService systemService) {
    return IntegrationFlows.from("findUserEnricherChannel")
            .enrich(enricherSpec ->
                    enricherSpec//.requestChannel("findUserServiceChannel")
                            .<User>propertyFunction("email", (message) ->
                                    (message.getPayload()).getEmail()
                            ).<User>propertyFunction("password", (message) ->
                            (message.getPayload()).getPassword()
                    ))
            .get();
}

@Bean
public IntegrationFlow findUserServiceFlow(SystemService systemService) {
    return IntegrationFlows.
            from("findUserServiceChannel")
            .<User>handle((p, h) -> systemService.findUser(p))
            .get();
}

可以用更简洁的方式重写:

@Bean
public IntegrationFlow findUserEnricherFlow(SystemService systemService) {
    return IntegrationFlows.from("findUserEnricherChannel")
            .enrich(enricherSpec ->
                    enricherSpec//.requestChannel("findUserServiceChannel")
                            .<User>propertyFunction("email", (message) ->
                                    (message.getPayload()).getEmail()
                            ).<User>propertyFunction("password", (message) ->
                            (message.getPayload()).getPassword()
                    ))
            .<User>handle((p, h) -> systemService.findUser(p))
            .get();
}

另一种选择:

@Bean
public IntegrationFlow findUserEnricherFlow(SystemService systemService) {
    return IntegrationFlows.from("findUserEnricherChannel")
            .enrich(enricherSpec ->
                    enricherSpec.requestSubFlow(flow -> flow.<User>handle((p, h) -> systemService.findUser(p))
                    ).<User>propertyFunction("email", (message) ->
                            (message.getPayload()).getEmail()
                    ).<User>propertyFunction("password", (message) ->
                            (message.getPayload()).getPassword()
                    ))
            .get();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-22
    • 2020-08-12
    • 1970-01-01
    • 1970-01-01
    • 2015-02-03
    • 2020-07-11
    • 1970-01-01
    相关资源
    最近更新 更多