简体   繁体   English

Spring 6: Spring 云 Stream Kafka - 替代@EnableBinding

[英]Spring 6: Spring Cloud Stream Kafka - Replacement for @EnableBinding

I was reading "Spring Microservices In Action (2021)" because I wanted to brush up on Microservices.我正在阅读“Spring Microservices In Action (2021)”,因为我想温习一下微服务。

Now with Spring Boot 3 a few things changed.现在有了 Spring Boot 3,一些事情发生了变化。 In the book, an easy example of how to push messages to a topic and how to consume messages to a topic were presented.书中提供了一个简单的示例,说明如何将消息推送到主题以及如何使用主题消息。

The Problem is: The examples presented do just not work with Spring Boot 3. Sending Messages from a Spring Boot 2 Project works.问题是:提供的示例不适用于 Spring Boot 3。从 Spring Boot 2 项目发送消息有效。 The underlying project can be found here:基础项目可以在这里找到:

https://github.com/ihuaylupo/manning-smia/tree/master/chapter10 https://github.com/ihuaylupo/manning-smia/tree/master/chapter10

Example 1 (organization-service):示例 1(组织服务):

Consider this Config:考虑这个配置:

spring.cloud.stream.bindings.output.destination=orgChangeTopic
spring.cloud.stream.bindings.output.content-type=application/json
spring.cloud.stream.kafka.binder.zkNodes=kafka #kafka is used as a network alias in docker-compose
spring.cloud.stream.kafka.binder.brokers=kafka

And this Component(Class) which can is injected in a service in this project而这个 Component(Class) 可以注入到这个项目的服务中

@Component
public class SimpleSourceBean {
    private Source source;

    private static final Logger logger = LoggerFactory.getLogger(SimpleSourceBean.class);

    @Autowired
    public SimpleSourceBean(Source source){
        this.source = source;
    }

    public void publishOrganizationChange(String action, String organizationId){
       logger.debug("Sending Kafka message {} for Organization Id: {}", action, organizationId);
        OrganizationChangeModel change =  new OrganizationChangeModel(
                OrganizationChangeModel.class.getTypeName(),
                action,
                organizationId,
                UserContext.getCorrelationId());

        source.output().send(MessageBuilder.withPayload(change).build());
    }
}

This code fires a message to the topic (destination) orgChangeTopic.此代码向主题(目标)orgChangeTopic 发送消息。 The way I understand it, the firsttime a message is fired, the topic is created.按照我的理解,第一次触发消息时,就会创建主题。

Question 1: How do I do this Spring Boot 3?问题一:这个Spring Boot 3怎么办? Config-Wise and "Code-Wise"?配置明智和“代码明智”?


Example 2:示例 2:

Consider this config:考虑这个配置:

spring.cloud.stream.bindings.input.destination=orgChangeTopic
spring.cloud.stream.bindings.input.content-type=application/json
spring.cloud.stream.bindings.input.group=licensingGroup
spring.cloud.stream.kafka.binder.zkNodes=kafka
spring.cloud.stream.kafka.binder.brokers=kafka

And this code:这段代码:

@SpringBootApplication
@RefreshScope
@EnableDiscoveryClient
@EnableFeignClients
@EnableEurekaClient
@EnableBinding(Sink.class)
public class LicenseServiceApplication {


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

    @StreamListener(Sink.INPUT)
    public void loggerSink(OrganizationChangeModel orgChange) {
        log.info("Received an {} event for organization id {}",
                orgChange.getAction(), orgChange.getOrganizationId());
    }

What this method is supposed to do is to fire whenever a message is fired in orgChangeTopic, we want the method loggerSink to fire.这个方法应该做的是在 orgChangeTopic 中触发消息时触发,我们希望方法 loggerSink 触发。

How do I do this in Spring Boot 3?我如何在 Spring Boot 3 中执行此操作?

In Spring Cloud Stream 4.0.0 (the version used if you are using Boot 3), a few things are removed - such as the EnableBinding, StreamListener, etc. We deprecated them before in 3.x and finally removed them in the 4.0.0 version.在 Spring Cloud Stream 4.0.0 (使用 Boot 3 时使用的版本)中,删除了一些内容 - 例如EnableBinding, StreamListener,等。我们之前在3.x中弃用了它们,最终在4.0.0版本。 The annotation-based programming model is removed in favor of the functional programming style enabled through the Spring Cloud Function project.基于注释的编程 model 被删除,支持通过 Spring Cloud Function 项目启用的函数式编程风格。 You essentially express your business logic as java.util.function.Funciton|Consumer|Supplier etc. for a processor, sink, and source, respectively.您基本上将业务逻辑表达为java.util.function.Funciton|Consumer|Supplier等,分别用于处理器、接收器和源。 For ad-hoc source situations, as in your first example, Spring Cloud Stream provides a StreamBridge API for custom sends.对于临时源情况,如您的第一个示例,Spring Cloud Stream 为自定义发送提供了StreamBridge API。

Your example #1 can be re-written like this:您的示例 #1 可以这样重写:

@Component
public class SimpleSourceBean {
    
    @Autowired
    StreamBridge streamBridge

    public void publishOrganizationChange(String action, String organizationId){
       logger.debug("Sending Kafka message {} for Organization Id: {}", action, organizationId);
        OrganizationChangeModel change =  new OrganizationChangeModel(
                OrganizationChangeModel.class.getTypeName(),
                action,
                organizationId,
                UserContext.getCorrelationId());

        streamBridge.send("output-out-0", MessageBuilder.withPayload(change).build());
    }
}

Config配置

spring.cloud.stream.bindings.output-out-0.destination=orgChangeTopic
spring.cloud.stream.kafka.binder.brokers=kafka

Just so you know, you no longer need that zkNode property.正如你所知,你不再需要那个 zkNode 属性。 Neither the content type since the framework auto-converts that for you.内容类型都不是,因为框架会自动为您转换。

StreamBridge send takes a binding name and the payload. StreamBridge发送采用绑定名称和有效负载。 The binding name can be anything - but for consistency reasons, we used output-out-0 here.绑定名称可以是任何东西——但出于一致性原因,我们在这里使用output-out-0 Please read the reference docs for more context around the reasoning for this binding name.请阅读参考文档以了解有关此绑定名称的更多上下文。

If you have a simple source that runs on a timer, you can express this simply as a supplier as below (instead of using a StreamBrdige ).如果您有一个在计时器上运行的简单源,您可以将其简单地表示为如下供应商(而不是使用StreamBrdige )。

@Bean
public Supplier<OrganizationChangeModel> ouput() {
  return () -> {
    // return the payload
  };
}

spring.cloud.function.definition=output
spring.cloud.bindings.output-out-0.destination=...

Example #2例子#2

@Bean
public Consumer<OrganizationChangeModel> loggerSink() {
 return model -> {        
   log.info("Received an {} event for organization id {}",
                orgChange.getAction(), orgChange.getOrganizationId());
   };
}

Config:配置:

spring.cloud.function.definition=loggerSink
spring.cloud.stream.bindings.loggerSink-in-0.destination=orgChangeTopic
spring.cloud.stream.bindings.loggerSinnk-in-0.group=licensingGroup
spring.cloud.stream.kafka.binder.brokers=kafka

If you want the input/output binding names to be specifically input or output rather than with in-0 , out-0 etc., there are ways to make that happen.如果您希望输入/输出绑定名称专门为inputoutput而不是in-0out-0等,有多种方法可以实现。 Details for this are in the reference docs.有关详细信息,请参阅参考文档。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM