首页 > 解决方案 > 如何使用 spring 集成 java DSL 实现丰富器?

问题描述

我想使用 java DSL重写以下 xml 示例

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);

它最终调用findUserByUsername方法SystemService

public User findUserByUsername(String username) 

因为客户端代码使用Userservice内部有 2 个转换:

  1. 在途中(SystemService#findUserByUsername调用之前),因为Userservice#findUserWithUsernameInMap接受Map<String, Object>SystemService#findUserByUsername接受字符串

  2. 在返回途中(SystemService#findUserByUsername调用后),因为SystemService#findUserByUsername返回用户但Userservice#findUserWithUsernameInMap返回Map<String, Object>

这些转换在 xml 配置中究竟是在哪里声明的?

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

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

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

标签: javaspringspring-integrationspring-integration-dsl

解决方案


的 Java DSL 等价物<int:enricher>.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();
}

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


推荐阅读