编程模型

本节介绍Spring Cloud Stream的编程模型。Spring Cloud Stream提供了许多预定义的注释,用于声明绑定的输入和输出通道,以及如何收听频道。

声明和绑定频道

触发绑定@EnableBinding

您可以将Spring应用程序转换为Spring Cloud Stream应用程序,将@EnableBinding注释应用于应用程序的配置类之一。@EnableBinding注释本身使用@Configuration进行元注释,并触发Spring Cloud Stream基础架构的配置:

...

@Import(...)

@Configuration

@EnableIntegration

public @interface EnableBinding {

    ...

    Class[] value() default {};

}

@EnableBinding注释可以将一个或多个接口类作为参数,这些接口类包含表示可绑定组件(通常是消息通道)的方法。

注意在Spring Cloud Stream 1.0中,唯一支持的可绑定组件是Spring消息传递MessageChannel及其扩展名SubscribableChannel和PollableChannel。未来版本应该使用相同的机制将此支持扩展到其他类型的组件。在本文档中,我们将继续参考渠道。

@Input和@Output

Spring Cloud Stream应用程序可以在接口中定义任意数量的输入和输出通道为@Input和@Output方法:

public interface Barista {

    @Input

    SubscribableChannel orders();

    @Output

    MessageChannel hotDrinks();

    @Output

    MessageChannel coldDrinks();

}

使用此接口作为参数@EnableBinding将分别触发三个绑定的通道名称为orders,hotDrinks和coldDrinks。

@EnableBinding(Barista.class)

public class CafeConfiguration {

  ...

}

自定义频道名称

使用@Input和@Output注释,您可以指定频道的自定义频道名称,如以下示例所示:

public interface Barista {

    ...

    @Input("inboundOrders")

    SubscribableChannel orders();

}

在这个例子中,创建的绑定通道将被命名为inboundOrders。

Source,Sink和Processor

为了方便寻址最常见的用例,涉及输入通道,输出通道或两者,Spring Cloud Stream提供了开箱即用的三个预定义接口。

Source可用于具有单个出站通道的应用程序。

public interface Source {

  String OUTPUT = "output";

  @Output(Source.OUTPUT)

  MessageChannel output();

}

Sink可用于具有单个入站通道的应用程序。

public interface Sink {

  String INPUT = "input";

  @Input(Sink.INPUT)

  SubscribableChannel input();

}

Processor可用于具有入站通道和出站通道的应用程序。

public interface Processor extends Source, Sink {

}

Spring Cloud Stream不为任何这些接口提供特殊处理; 它们只是开箱即用。

访问绑定通道

注入绑定界面

对于每个绑定接口,Spring Cloud Stream将生成一个实现该接口的bean。调用其中一个bean的@Input注释或@Output注释方法将返回相关的绑定通道。

以下示例中的bean在调用其hello方法时在输出通道上发送消息。它在注入的Sourcebean上调用output()来检索目标通道。

@Component

public class SendingBean {

    private Source source;

    @Autowired

    public SendingBean(Source source) {

        this.source = source;

    }

    public void sayHello(String name) {

        source.output().send(MessageBuilder.withPayload(name).build());

    }

}

直接注入渠道

绑定通道也可以直接注入:

@Component

public class SendingBean {

    private MessageChannel output;

    @Autowired

    public SendingBean(MessageChannel output) {

        this.output = output;

    }

    public void sayHello(String name) {

        output.send(MessageBuilder.withPayload(name).build());

    }

}

如果在声明注释上定制了通道的名称,则应使用该名称而不是方法名称。给出以下声明:

public interface CustomSource {

    ...

    @Output("customOutput")

    MessageChannel output();

}

通道将被注入,如下例所示:

@Component

public class SendingBean {

    private MessageChannel output;

    @Autowired

    public SendingBean(@Qualifier("customOutput") MessageChannel output) {

        this.output = output;

    }

    public void sayHello(String name) {

        this.output.send(MessageBuilder.withPayload(name).build());

    }

}

生产和消费消息

您可以使用Spring Integration注解或Spring Cloud Stream的@StreamListener注释编写Spring Cloud Stream应用程序。@StreamListener注释在其他Spring消息传递注释(例如@MessageMapping,@JmsListener,@RabbitListener等)之后建模,但添加内容类型管理和类型强制功能。

本地Spring Integration支持

由于Spring Cloud Stream基于Spring Integration,Stream完全继承了Integration的基础和基础架构以及组件本身。例如,您可以将Source的输出通道附加到MessageSource:

@EnableBinding(Source.class)

public class TimerSource {

  @Value("${format}")

  private String format;

  @Bean

  @InboundChannelAdapter(value = Source.OUTPUT, poller = @Poller(fixedDelay = "${fixedDelay}", maxMessagesPerPoll = "1"))

  public MessageSource timerMessageSource() {

    return () -> new GenericMessage<>(new SimpleDateFormat(format).format(new Date()));

  }

}

或者您可以在变压器中使用处理器的通道:

@EnableBinding(Processor.class)

public class TransformProcessor {

  @Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)

  public Object transform(String message) {

    return message.toUpperCase();

  }

}

Spring Integration错误通道支持

Spring Cloud Stream支持发布Spring Integration全局错误通道收到的错误消息。发送到errorChannel的错误消息可以通过为名为error的出站目标配置绑定,将其发布到代理的特定目标。例如,要将错误消息发布到名为“myErrors”的代理目标,请提供以下属性:spring.cloud.stream.bindings.error.destination=myErrors

使用@StreamListener进行自动内容类型处理

Spring Integration支持Spring Cloud Stream提供自己的@StreamListener注释,以其他Spring消息传递注释(例如@MessageMapping,@JmsListener,@RabbitListener等) )。@StreamListener注释提供了一种更简单的处理入站邮件的模型,特别是在处理涉及内容类型管理和类型强制的用例时。

Spring Cloud Stream提供了一种可扩展的MessageConverter机制,用于通过绑定通道处理数据转换,并且在这种情况下,将调度到使用@StreamListener注释的方法。以下是处理外部Vote事件的应用程序的示例:

@EnableBinding(Sink.class)

public class VoteHandler {

  @Autowired

  VotingService votingService;

  @StreamListener(Sink.INPUT)

  public void handle(Vote vote) {

    votingService.record(vote);

  }

}

当考虑String有效载荷和contentType标题application/json的入站Message时,可以看到@StreamListener和Spring Integration@ServiceActivator之间的区别。在@StreamListener的情况下,MessageConverter机制将使用contentType标头将String有效载荷解析为Vote对象。

与其他Spring消息传递方法一样,方法参数可以用@Payload,@Headers和@Header注释。

注意对于返回数据的方法,您必须使用@SendTo注释来指定方法返回的数据的输出绑定目的地:

@EnableBinding(Processor.class)

public class TransformProcessor {

  @Autowired

  VotingService votingService;

  @StreamListener(Processor.INPUT)

  @SendTo(Processor.OUTPUT)

  public VoteResult handle(Vote vote) {

    return votingService.record(vote);

  }

}

使用@StreamListener将消息分派到多个方法

自1.2版本以来,Spring Cloud Stream支持根据条件向在输入通道上注册的多个@StreamListener方法发送消息。

为了有资格支持有条件的调度,一种方法必须满足以下条件:

它不能返回值

它必须是一个单独的消息处理方法(不支持的反应API方法)

条件通过注释的condition属性中的SpEL表达式指定,并为每个消息进行评估。匹配条件的所有处理程序将在同一个线程中被调用,并且不必对调用发生的顺序做出假设。

使用@StreamListener具有调度条件的示例可以在下面看到。在此示例中,带有值为foo的标题type的所有消息将被分派到receiveFoo方法,所有带有值为bar的标题type的消息将被分派到receiveBar方法。

@EnableBinding(Sink.class)

@EnableAutoConfiguration

public static class TestPojoWithAnnotatedArguments {

    @StreamListener(target = Sink.INPUT, condition = "headers['type']=='foo'")

    public void receiveFoo(@Payload FooPojo fooPojo) {

      // handle the message

    }

    @StreamListener(target = Sink.INPUT, condition = "headers['type']=='bar'")

    public void receiveBar(@Payload BarPojo barPojo) {

      // handle the message

    }

}

注意仅通过@StreamListener条件进行调度仅对单个消息的处理程序支持,而不适用于无效编程支持(如下所述)。

你可能感兴趣的:(编程模型)