将AggregateApplicationBuilder与HTTP Source绑定一起使用

时间:2018-12-19 02:20:49

标签: spring-boot spring-cloud-stream

我的目标是创建一个可以由REST端点调用的同步过程。在我的实际需求中,这将处理来自Web界面的用户编辑,而异步管道则由设置为单独服务的相同进程组成,以处理通过事件流发送的数据。我们希望HTTP调用是同步的,以便在整个过程中进行编辑后即可立即显示结果。

就下面的示例而言,我有一个源,一个进程和一个接收器。我想使用Spring Cloud Stream的AggregateApplicationBuilder使用RestController作为源创建流程的聚合,但是下面的示例仅创建应用程序,并在完全连接好后立即将其关闭。

是否可以通过这种方式使用AggregateApplicationBuilder?我一直无法弄清楚如何使生成的AggregateApplication作为Web应用程序运行。

应用程序类:

package com.example.aggregate;

import com.example.aggregate.controller.FooController;
import com.example.aggregate.processor.BarProcess;
import com.example.aggregate.sink.SinkService;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.aggregate.AggregateApplicationBuilder;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        new AggregateApplicationBuilder()
            .web(true)
            .from(FooController.class)
            .via(BarProcess.class)
            .to(SinkService.class)
            .run(args);
    }
}

作为来源的控制器:

package com.example.aggregate.controller;

import com.example.aggregate.dto.Foo;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.Instant;
import java.util.HashMap;

@RestController
@RequestMapping("/v1/foo")
@EnableBinding(Source.class)
public class FooController {

    private Source source;

    public FooController(Source source) {
        this.source = source;
    }

    @PostMapping
    public void handleRequest(@RequestBody Foo foo) {
        foo.putValue("Received", Instant.now().toString());
        sendMessage(foo);
    }

    private void sendMessage(Foo foo) {
        Message<Foo> message = MessageBuilder.createMessage(foo, new MessageHeaders(new HashMap<>()));
        source.output().send(message);
    }
}

处理器:

package com.example.aggregate.processor;

import com.example.aggregate.dto.Foo;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Processor;
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.support.MessageBuilder;

@EnableBinding(Processor.class)
public class BarProcess {
    @StreamListener(Processor.INPUT)
    @SendTo(Processor.OUTPUT)
    public Message<Foo> doFoo(Message<Foo> message) {
        Foo foo = message.getPayload();
        foo.putValue("BarProcess", "completed");
        return MessageBuilder.createMessage(foo, message.getHeaders());
    }
}

接收器类(目前,我只是尝试将结果记录到System.out中):

package com.example.aggregate.sink;

import com.example.aggregate.dto.Foo;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Service;

@Service
@EnableBinding(Sink.class)
public class SinkService {

    @StreamListener(Sink.INPUT)
    public void processPayload(Message<Foo> payload) {
        System.out.println("*****SINK*****");
        System.out.println("Received: " + payload);
    }
}

最后是简单的Foo类:

package com.example.aggregate.dto;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;

import java.util.HashMap;
import java.util.Map;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class Foo {

    private Map<String, String> values;

    public void putValue(String key, String value) {
        if (values == null)
            values = new HashMap<>();
        values.put(key, value);
    }

    public Map<String, String> getValues() {
        return values;
    }
}

运行Spring应用程序时的输出是:

2018-12-18 18:12:00.104  INFO 94095 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@1bd4fdd: startup date [Tue Dec 18 18:12:00 PST 2018]; root of context hierarchy
2018-12-18 18:12:00.301  INFO 94095 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'configurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$a4218ca6] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.2.RELEASE)

2018-12-18 18:12:00.398  INFO 94095 --- [           main] c.e.aggregate.SyncPipelineApplication    : The following profiles are active: local
2018-12-18 18:12:00.408  INFO 94095 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@6a57ae10: startup date [Tue Dec 18 18:12:00 PST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@1bd4fdd
2018-12-18 18:12:00.475  INFO 94095 --- [           main] o.s.i.config.IntegrationRegistrar        : No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created.
2018-12-18 18:12:00.519  INFO 94095 --- [           main] faultConfiguringBeanFactoryPostProcessor : No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created.
2018-12-18 18:12:00.521  INFO 94095 --- [           main] faultConfiguringBeanFactoryPostProcessor : No bean named 'taskScheduler' has been explicitly defined. Therefore, a default ThreadPoolTaskScheduler will be created.
2018-12-18 18:12:00.705  INFO 94095 --- [           main] o.s.s.c.ThreadPoolTaskScheduler          : Initializing ExecutorService  'taskScheduler'
2018-12-18 18:12:00.864  INFO 94095 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase -2147482648
2018-12-18 18:12:00.864  INFO 94095 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 0
2018-12-18 18:12:00.864  INFO 94095 --- [           main] o.s.i.endpoint.EventDrivenConsumer       : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
2018-12-18 18:12:00.864  INFO 94095 --- [           main] o.s.i.channel.PublishSubscribeChannel    : Channel 'application-1.errorChannel' has 1 subscriber(s).
2018-12-18 18:12:00.864  INFO 94095 --- [           main] o.s.i.endpoint.EventDrivenConsumer       : started _org.springframework.integration.errorLogger
2018-12-18 18:12:00.865  INFO 94095 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 2147482647
2018-12-18 18:12:00.869  INFO 94095 --- [           main] c.e.aggregate.SyncPipelineApplication    : Started SyncPipelineApplication in 1.089 seconds (JVM running for 1.438)
2018-12-18 18:12:00.891  INFO 94095 --- [           main] com.example.aggregate.sink.SinkService   : The following profiles are active: local
2018-12-18 18:12:00.893  INFO 94095 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@54227100: startup date [Tue Dec 18 18:12:00 PST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@6a57ae10
2018-12-18 18:12:01.024  INFO 94095 --- [           main] o.s.integration.channel.DirectChannel    : Channel 'application-1-1.input' has 1 subscriber(s).
2018-12-18 18:12:01.024  INFO 94095 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase -2147482648
2018-12-18 18:12:01.024  INFO 94095 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 2147482647
2018-12-18 18:12:01.027  INFO 94095 --- [           main] com.example.aggregate.sink.SinkService   : Started SinkService in 0.153 seconds (JVM running for 1.596)
2018-12-18 18:12:01.044  INFO 94095 --- [           main] c.e.aggregate.processor.BarProcess       : The following profiles are active: local
2018-12-18 18:12:01.046  INFO 94095 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@35fe2125: startup date [Tue Dec 18 18:12:01 PST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@6a57ae10
2018-12-18 18:12:01.143  INFO 94095 --- [           main] o.s.integration.channel.DirectChannel    : Channel 'application-1-2.input' has 1 subscriber(s).
2018-12-18 18:12:01.144  INFO 94095 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase -2147482648
2018-12-18 18:12:01.144  INFO 94095 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 2147482647
2018-12-18 18:12:01.145  INFO 94095 --- [           main] c.e.aggregate.processor.BarProcess       : Started BarProcess in 0.116 seconds (JVM running for 1.714)
2018-12-18 18:12:01.158  INFO 94095 --- [           main] c.e.aggregate.controller.FooController   : The following profiles are active: local
2018-12-18 18:12:01.162  INFO 94095 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@48c40605: startup date [Tue Dec 18 18:12:01 PST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@6a57ae10
2018-12-18 18:12:01.244  INFO 94095 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase -2147482648
2018-12-18 18:12:01.244  INFO 94095 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 2147482647
2018-12-18 18:12:01.246  INFO 94095 --- [           main] c.e.aggregate.controller.FooController   : Started FooController in 0.1 seconds (JVM running for 1.815)
2018-12-18 18:12:01.247  INFO 94095 --- [       Thread-5] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@6a57ae10: startup date [Tue Dec 18 18:12:00 PST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@1bd4fdd
2018-12-18 18:12:01.248  INFO 94095 --- [       Thread-5] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@54227100: startup date [Tue Dec 18 18:12:00 PST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@6a57ae10
2018-12-18 18:12:01.248  INFO 94095 --- [       Thread-5] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 2147482647
2018-12-18 18:12:01.249  INFO 94095 --- [       Thread-5] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase -2147482648
2018-12-18 18:12:01.249  INFO 94095 --- [       Thread-5] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@35fe2125: startup date [Tue Dec 18 18:12:01 PST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@6a57ae10
2018-12-18 18:12:01.250  INFO 94095 --- [       Thread-5] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 2147482647
2018-12-18 18:12:01.250  INFO 94095 --- [       Thread-5] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase -2147482648
2018-12-18 18:12:01.250  INFO 94095 --- [       Thread-5] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@48c40605: startup date [Tue Dec 18 18:12:01 PST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@6a57ae10
2018-12-18 18:12:01.250  INFO 94095 --- [       Thread-5] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 2147482647
2018-12-18 18:12:01.250  INFO 94095 --- [       Thread-5] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase -2147482648
2018-12-18 18:12:01.251  INFO 94095 --- [       Thread-5] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 2147482647
2018-12-18 18:12:01.251  INFO 94095 --- [       Thread-5] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 0
2018-12-18 18:12:01.251  INFO 94095 --- [       Thread-5] o.s.i.endpoint.EventDrivenConsumer       : Removing {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
2018-12-18 18:12:01.251  INFO 94095 --- [       Thread-5] o.s.i.channel.PublishSubscribeChannel    : Channel 'application-1.errorChannel' has 0 subscriber(s).
2018-12-18 18:12:01.251  INFO 94095 --- [       Thread-5] o.s.i.endpoint.EventDrivenConsumer       : stopped _org.springframework.integration.errorLogger
2018-12-18 18:12:01.251  INFO 94095 --- [       Thread-5] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase -2147482648
2018-12-18 18:12:01.252  INFO 94095 --- [       Thread-5] o.s.s.c.ThreadPoolTaskScheduler          : Shutting down ExecutorService 'taskScheduler'

Process finished with exit code 0

有关如何保持应用程序运行的任何指导?当我用一个使用InboundChannelAdapter的控制器源替换控制器源时,它会按照我期望的方式工作,并根据轮询时间发送消息。

提前谢谢

1 个答案:

答案 0 :(得分:2)

David,虽然我们尚未真正宣布任何正式声明,但AggregatorBuilder实际上已被弃用;)我们不再赘述,您可能会注意到,最新的快照文档不再提供有关此部分的内容。

这意味着我们可以通过功能组合来更好,更简单地满足您的需求。目前,我们正在博客上发布Spring Cloud Stream的2.1.0.RELEASE版本,该版本将于1月初发布(我们现在位于RC4中),因此首先您需要切换到使用最新版本版本。

现在,支持是通过在Spring Cloud Stream中添加Spring Cloud Function编程模型来实现的。您可以详细了解here。 另外,不久前在此论坛上也提出了类似的问题,因此this link应该为您提供所需的答案。实际上,它引用了GitHub上使用Http源的示例应用程序,本质上展示了一个相同的情况。

请仔细阅读,如果您仍有任何问题,请告诉我们。

干杯, 奥列格(Oleg)