【问题标题】:What is analog of <int:gateway xml tag in java DSL in spring - integration?java DSL中的<int:gateway xml标签在spring中的模拟-集成是什么?
【发布时间】:2019-08-29 11:24:33
【问题描述】:

我想使用 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$0(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$0(<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

附言

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

@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 魔法进行转换?

【问题讨论】:

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


    【解决方案1】:

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

    查看 Wiki 页面顶部的横幅

    该项目已被 Spring Integration Core 从 5.0 版开始吸收。有关实际文档,请参阅其参考手册。此项目仅处于维护、错误修复状态。

    the current documentation - IntegrationFlow as Gateway

    IntegrationFlow 可以从提供 GatewayProxyFactoryBean 组件的服务接口开始,如下例所示:

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

    【讨论】:

    • 但是如何设置接口方法和一些真实方法调用之间的映射呢?
    • 在您的示例中,ControlBusGateway 只有一种方法,但 UserService 有 3 种不同的方法
    • 您可以使用多种方法,只要它们都进入同一个流程即可。当每种方法转到不同的通道时,没有直接的 DSL 等效项;使用 DSL 时,我们会使用 .from(UserService.class).route(// routing based on method called header)
    • 我可以使用 HeaderValueRouter 吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-03
    • 2020-07-11
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 2017-01-27
    相关资源
    最近更新 更多