什么是 spring 中 java DSL 中的 <int:gateway xml 标记的模拟 - 集成?

What is analog of <int:gateway xml tag in java DSL in spring - integration?

我想使用 java DSL 重写以下 xml configured example

现在我坚持以下配置部分:

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

我试图找到任何模拟here但我没有找到。

你能帮我找到吗?

更新

我尝试编写以下代码:

配置:

@Bean
public IntegrationFlow findUserEnricherChannelFlow() {
    return IntegrationFlows.from(UserService.class)
            .handle(SystemService.class, "findUser") // I have no idea how to map all methods
            .get();
}

祈求者:

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

用户服务:

public interface UserService {

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

    /**
     * Retrieves a user based on the provided user. User object is routed to the
     * "findUserByUsernameEnricherChannel" channel.
     */
    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.
     */
    Map<String, Object> findUserWithUsernameInMap(Map<String, Object> userdata);

}

系统服务:

public class SystemService {

    private static final Log LOGGER = LogFactory.getLog(SystemService.class);

    /** Default Constructor. */
    public SystemService() {
        super();
    }

    public User findUser(User user) {

        LOGGER.info(String.format("Calling method 'findUser' with parameter %s", user));

        final User fullUser = new User(user.getUsername(),
                                       "secret",
                                       user.getUsername() + "@springintegration.org");
        return fullUser;
    }

    public User findUserByUsername(String username) {

        LOGGER.info(String.format("Calling method 'findUserByUsername' with parameter: %s", username));

        return new User(username, "secret", username + "@springintegration.org");

    }

}

但在这种情况下,应用程序无法从以下跟踪开始:

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-08-29 16:04:54.293 ERROR 7948 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'findUserEnricherChannelFlow' defined in class path resource [enricher/Config.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.integration.dsl.IntegrationFlow]: Factory method 'findUserEnricherChannelFlow' threw exception; nested exception is java.lang.IllegalStateException: Target object of type [class java.lang.Class] has no eligible methods for handling Messages.
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:627) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:456) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean[=18=](AbstractBeanFactory.java:320) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:845) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:742) ~[spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:389) ~[spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:311) ~[spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
    at enricher.MyApplication.main(MyApplication.java:13) ~[classes/:na]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.integration.dsl.IntegrationFlow]: Factory method 'findUserEnricherChannelFlow' threw exception; nested exception is java.lang.IllegalStateException: Target object of type [class java.lang.Class] has no eligible methods for handling Messages.
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    ... 17 common frames omitted
Caused by: java.lang.IllegalStateException: Target object of type [class java.lang.Class] has no eligible methods for handling Messages.
    at org.springframework.util.Assert.state(Assert.java:94) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.integration.handler.support.MessagingMethodInvokerHelper.findHandlerMethodsForTarget(MessagingMethodInvokerHelper.java:898) ~[spring-integration-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.integration.handler.support.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:293) ~[spring-integration-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.integration.handler.support.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:223) ~[spring-integration-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.integration.handler.support.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:227) ~[spring-integration-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.integration.handler.MethodInvokingMessageProcessor.<init>(MethodInvokingMessageProcessor.java:54) ~[spring-integration-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.integration.handler.ServiceActivatingHandler.<init>(ServiceActivatingHandler.java:46) ~[spring-integration-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.integration.dsl.IntegrationFlowDefinition.handle(IntegrationFlowDefinition.java:996) ~[spring-integration-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.integration.dsl.IntegrationFlowDefinition.handle(IntegrationFlowDefinition.java:979) ~[spring-integration-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at enricher.Config.findUserEnricherChannelFlow(Config.java:36) ~[classes/:na]
    at enricher.Config$$EnhancerBySpringCGLIB$$f36636fe.CGLIB$findUserEnricherChannelFlow[=18=](<generated>) ~[classes/:na]
    at enricher.Config$$EnhancerBySpringCGLIB$$f36636fe$$FastClassBySpringCGLIB$$ada0b78a.invoke(<generated>) ~[classes/:na]
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at enricher.Config$$EnhancerBySpringCGLIB$$f36636fe.findUserEnricherChannelFlow(<generated>) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    ... 18 common frames omitted

P.S.

我提前做了几个步骤,现在我有以下配置:

@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 {

    private static final Log LOGGER = LogFactory.getLog(SystemService.class);

    /** Default Constructor. */
    public SystemService() {
        super();
    }

    public User findUser(User user) {

        LOGGER.info(String.format("Calling method 'findUser' with parameter %s", user));

        final User fullUser = new User(user.getUsername(),
                                       "secret",
                                       user.getUsername() + "@springintegration.org");
        return fullUser;
    }

    public User findUserByUsername(String username) {

        LOGGER.info(String.format("Calling method 'findUserByUsername' with parameter: %s", username));

        return new User(username, "secret", username + "@springintegration.org");

    }

}

主要方法:

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 魔术来进行转换?

该文档适用于 Spring Integration 4.3 的旧版本 DSL;从 5.0 版本开始,DSL 被集成到主项目和文档中。该版本中不存在网关功能。

查看 Wiki 页面顶部的横幅

This project has been absorbed by Spring Integration Core starting with version 5.0. Please consult its Reference Manual for the actual documentation. This project is only in a maintenance, bug fixing state.

the current documentation - IntegrationFlow as Gateway

The IntegrationFlow can start from the service interface that provides a GatewayProxyFactoryBean component, as the following example shows:

public interface ControlBusGateway {

    void send(String command);
}

...

@Bean
public IntegrationFlow controlBusFlow() {
    return IntegrationFlows.from(ControlBusGateway.class)
            .controlBus()
            .get();
}

该示例应用程序的工作原理相同

public interface RequestGateway {

    String echo(String request);

}

....from(RequestGateway.class)
...

编辑

DSL网关目前不支持多通道多路网关。您可以使用一些技巧...


@SpringBootApplication
@IntegrationComponentScan // finds the messaging gateway
public class So57709118Application {

    public static void main(String[] args) {
        SpringApplication.run(So57709118Application.class, args);
    }

    @Bean
    public IntegrationFlow flow() {
        return IntegrationFlows.from("gatewayChannel")
                //.route(...)
                .log()
                .nullChannel();
    }


    @Bean
    @DependsOn("flow")
    public ApplicationRunner runner(Gate gate) {
        return args -> {
            gate.method1("bar");
            gate.method2("bar");
        };
    }

}

@MessagingGateway(defaultRequestChannel = "gatewayChannel",
        defaultHeaders = @GatewayHeader(name = "method", expression = "#gatewayMethod.name"))
interface Gate {

    void method1(String foo);

    void method2(String foo);

}

或者,您可以在每个方法上设置 requestChannel,而不是所有的通用流程

@MessagingGateway(defaultHeaders = @GatewayHeader(name = "method", expression = "#gatewayMethod.name"))
interface Gate {

    @Gateway(requestChannel = "foo")
    void method1(String foo);

    @Gateway(requestChannel = "bar")
    void method2(String foo);

}