Original link: https://piotrminkowski.wordpress.com/2018/06/15/ BUILDING-AND-TESTING-MESSAGE-DRIVEN-MICROSERVICES-USING-SPRING-CLOUD-STREAM/PIOTR Mińkowski Translator: helloworldtangimgspring Boot and Spring cloud provide you with a solution to quickly build microservices with different means of communication. You can create a sync rest microservices based on the spring cloud Netflix library, as I've shown in a previous article, using Spring Boot 2.0, Eureka and Spring Cloud to quickly build a micro-service guide. You can use the Spring Webflux project to create asynchronous, responsive microservices on Netty and combine them with some spring cloud libraries, as my article shows using Spring Webflux and Spring Cloud to build responsive microservices. Finally, you can use the spring Cloud stream and a broker like Apache Kafka or RABBITMQ to implement the Message-driven microservices based on the Publish/subscribe model. The final approach to building microservices is the main topic of this article. I'll show you how to build, scale, run, and test messaging microservices efficiently on the basis of RABBITMQ broker. Architecture in order to demonstrate the features of spring Cloud Stream, we will design a sample system that uses the Publish/subscribe model for cross-service communication. We have three micro services: Order-service, Product-service and Account-service. The application Order-service exposes the HTTP endpoint responsible for processing orders sent to our system. All incoming orders are--order-service prepared for asynchronous processing and send messages to RABBITMQ exchange, and then respond to the calling client without waiting for the message to be consumed before responding. The application's Account-service and Product-service are listening for order messages into the RABBITMQ exchange. The MicroServices Account-service is responsible for checking that the client's account has sufficient funds to cover the amount required for the order and, if any, to debit the account. Micro-service Product-service checkWhether there is sufficient inventory and change the number of available products after processing the order. Both Account-service and Product-service send asynchronous responses with an operational state through RABBITMQ Exchange, which is a one-to-two communication using direct exchange. The microservices Order-service updates the order status based on the received response message and is provided to the external client via rest endpoint Get/order/{id}. If you think our example description is a bit difficult to understand, here is a schema diagram for clarification. Stream-1 the recommended way to enable spring cloud stream to use spring cloud stream in a project is to use a dependency management system. Spring Cloud Stream has a dependency management that is related to the entire spring cloud framework and is independently released. However, if we have declared spring-cloud-dependencies in the Dependencymanagement section of the elmhurst.release version, we do not need to declare any other content in Pom.xml. If you prefer to use only the spring Cloud Stream project, then you should define the following sections. The next step is to add spring-cloud-streamartifact to the project dependencies. I also recommend that you include at least the Spring-cloud-sleuth library to provide traceid for sending messages that are sent as source requests into order-service. Spring Cloud Stream programming model to enable your application to connect to a message broker, use the @enablebinding annotation on the main class. @EnableBinding annotation takes one or more interfaces as parameters. You can choose between the three interfaces provided by spring Cloud stream: Sink: This is used to mark a service that receives messages from an inbound channel. Source: This is used to send messages to the outbound channel. Processor: When you need an inbound channel and an outbound channel, it can be used because it inherits the source and sink interfaces. Because Order-service sends messages and receives them, its main class already uses @enablebinding (processor.class) annotations. The following is the main class with the spring Cloud Stream binding enabled in the Order-service project. @SpriNgbootapplication@enablebinding (processor.class) public class Orderapplication {... public static void main (string[] args) {new Springapplicationbuilder (Orderapplication.class). Web (True). Run (args);} ...} Add message Broker in the spring Cloud stream terminology, the implementation that is responsible for integrating with a particular message broker is called Binder. By default, Spring Cloud Stream provides a binder implementation for Kafka and RABBITMQ. It can automatically detect and find binders on the classpath. Any middleware-specific settings can be overridden by the external configuration properties supported by spring boot, such as application parameters, environment variables, or just application.yml files. To include support for RABBITMQ, RABBITMQ uses this article as message broker, and you should add the following dependencies to your project. Now, our application needs to connect to a shared instance of RABBITMQ broker. That's why I'm using RABBITMQ to run the Docker image on the default port 5672. It can also start the Web dashboard under Address http://192.168.99.100:15672 (http://192.168.99.100:15672/). We need to override the default settings in spring Boot application by setting the property spring.rabbitmq.host to the Docker machine IP 192.168.99.100. Implementing a message-driven microservices spring Cloud stream was built on top of the spring integration project. Spring integration extends the Spring programming model to support the well-known enterprise integration Model (EIP). The EIP defines a number of classic components that are often used in distributed systems. You may have heard of patterns such as message channels, routers, aggregators, or endpoints. Let's go back to the example above. Let's start with Order-service, which takes care of orders, publishes them on a shared topic, and collects asynchronous responses from downstream services. Here is @service, which uses SOurcebean to build the message and publish it to the remote topic. This @Service is called by the controller, which exposes an HTTP endpoints that submits a new order and obtains an order status by ID. Now, let's take a closer look at the consumer side. The messages sent by Ordersender beans from Order-service are received by Account-service and Product-service. In order to receive messages from topic Exchange, we only need to add @StreamListener annotations on the method that the incoming parameter is Order. We also have to define the target channel for the listener-in this case, it is processor.input. For example: @StreamListener (processor.input) public void Receiveorder (order order) throws Jsonprocessingexception {Logger.info ("Order Received: {}", mapper.writevalueasstring (order)); Service.process (order); The receiving order is processed by Accountservicebean. Account-service will accept or reject orders based on whether there is sufficient funds in the client's account. The response of the acceptance status is sent back to Order-service through the output channel of the Ordersenderbean call. The final step is configuration. It is provided in the APPLICATION.YML. We must correctly define the destination of the channel. The Order-service assigns orders-outdestination to the output channel, while orders-indestination is the input channel, and Account-service and Product-service are the opposite. This is logical because the message sent through Order-service through its output destination is received through its input destination received by the service. But in shared broker's exchange, it is still the same destination. The following is the configuration settings for Order-service. Spring:application:name:order-service rabbitmq:host:192.168.99.100 POrt:5672 Cloud:stream:bindings:output:destination:orders-out producer:partitionKeyExpression:payload.customerId PA Rtitioncount:2 input:destination:orders-in Rabbit:bindings:input:consumer:exchangeType:direct This is for Account-service and The configuration provided by the Product-service. Finally, you can run the microservices in the example above. Now, we just need to run a single instance of each microservices. You can easily generate some test requests by running the JUnit test class ordercontrollertest, which is provided in the order-service provided in my source code library. This is a simple situation. In the next article, we'll learn more advanced examples that include multiple running consumer service instances. Extension in order to extend our spring Cloud stream application, we only need to launch an additional instance of each microservices. They will still listen for incoming messages in the same topic exchange as the currently running instance. After adding an instance of Account-service and Product-service, we can send a test order. The results of this test are not satisfactory to us ... Why? This order is received by all instances of each microservices run. This is exactly how topic exchanges works-messages sent to topic are received by all consumers and they are listening for this topic. Fortunately, Spring Cloud stream can solve this problem by providing a solution called consumer group. It is responsible for ensuring that a message is handled only by one instance if they are placed in a competing consumer relationship. When running multiple service instances, the conversion to the consumer group mechanism is already visualized in. Stream-2 the configuration of a consumer group mechanism is not very difficult. We only need to set the group parameter and give the name of the given destination. The following is the current binding configuration for Account-service. Orders-indestination is a queue created for direct communication with Order-service, so only orders-out is grouped so thatWith Spring.cloud.stream.bindings. The Group property. The Consumer group mechanism is a concept of Apache Kafka, which is also implemented in spring Cloud stream and applies to RABBITMQ broker, which does not natively support it. So I think its configuration on the RABBITMQ is very interesting. If you run two service instances in destination without setting the group name in destination, then there will be two bindings (one bindings per instance) created for a single exchange, as shown in. Because there are two applications listening in this exchange, there are a total of four binding allocations to that exchange. stream-3 If you set the group name for the selected destination Spring Cloud stream, a single binding will be created for all running instances of the given service. The name of the binding is suffixed with the group name. B08597_11_06 because we have included Spring-cloud-starter-sleuth in the project dependencies, when implementing a single request for Order-service POST endpoint, send the same between all asynchronous requests that are exchanged Traceid head. For this reason, we can use elastic Stack (Kibana) to easily correlate all the logs together. B08597_11_05 Automated Testing you can easily test your microservices without having to connect to message broker. To implement it, you need to include Spring-cloud-stream-test-support in your project dependencies. It contains Testsupportbinderbean, which allows you to interact with the binding channel and check any messages that the application sends and receives. In the test class, we need to declare messagecollectorbean, which is responsible for receiving messages reserved by Testsupportbinder. This is my Account-service test class. With Processorbean, I send the test order to the input channel. The messagecollector then receives a message that is sent back to Order-service through the output channel. The testaccepted of the test method creates the order that should be accepted by the account service, while the Testrejected method sets the order price too high, resulting in a rejection order. Summary when you do not need a synchronous response from the API, the Message-driven micro-serviceis a good choice. In this article, I showed sample use cases for the Publish/subscribe model in cross-service communication between your microservices. Source code is common on GitHub (https://github.com/helloworldtang/sample-message-driven-microservices.git "original source maven cannot run, This project fork the original code and fix the error "). For more interesting examples of using the spring Cloud Stream library, Apache Kafka, you can refer to the 11th chapter of my book, Mastering Spring Cloud (https://www.packtpub.com/ Application-development/mastering-spring-cloud). Focus on community numbers, join the community of pure Technology Group
Translate: Build and test Message-driven microservices based on spring Cloud stream