如何使用Spring Integraton Java DSL实现Richer?

时间:2019-08-30 13:22:10

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

我想使用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魔术进行转换?

P.S。

我认为Config类可以通过某种方式简化。我的意思是findUserByUsernameEnricherFlow findUserWithUsernameInMapFlow个方法

更新

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

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

它具有以下界面:

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

它最终调用findUserByUsername的{​​{1}}方法:

SystemService

由于客户端代码可与public User findUserByUsername(String username) 一起使用,因此内部有2种转换:

  1. (在Userservice调用之前),因为SystemService#findUserByUsername接受Userservice#findUserWithUsernameInMapMap<String, Object>接受String

  2. 在返回途中(在SystemService#findUserByUsername调用之后),因为SystemService#findUserByUsername返回用户,但SystemService#findUserByUsername返回Userservice#findUserWithUsernameInMap

这些转换到底在xml配置中声明了什么地方?

我建议您使用request-payload-expression来进行 TO 转换。看起来它可以以与Object相同的方式与Map一起使用。但是,BACK转换一点也不明确。确定配置具有

Map<String, Object>

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

2 个答案:

答案 0 :(得分:1)

<int:enricher>等效的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();
}

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

答案 1 :(得分:0)

最终,我能够将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();
}