The third day of spring cloud learning is the Silicon Valley version

11 zuul routing gateway

After skipping ~ a brain map will be sent, and zuul gateway can be seen on the brain map

12 Gateway next generation gateway


12.1 introduction

First, create a new module cloud gateway gateway 9527
pom

<dependencies>
        <!--gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- Introduce self defined api General package, you can use Payment payment Entity -->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--General basic configuration class-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

yml

server:
  port: 9527

spring:
  application:
    name: cloud-gateway

eureka:
  instance:
    hostname: cloud-gateway-service
  client: #The service provider is registered in the eureka service list
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

The main startup class needs to open the annotation registered in the eureka center

@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527
{
    public static void main(String[] args)
    {
        SpringApplication.run(GateWayMain9527.class,args);
    }
}

Because this is a gateway, we don't need a business class
Such a gateway is ready. How does the 9527 gateway do routing mapping???
At present, we do not want to expose the 8001 port. We hope to set a layer of 9527 outside the 8001

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_routh #payment_route    #The ID of the route. There are no fixed rules, but it is required to be unique. It is recommended to match the service name
          uri: http://localhost:8001 # matches the routing address of the service. / / that is, the forwarding address
          predicates:
            - Path=/payment/get/**         # Assert that the path matches the route / / that is, the interface

        - id: payment_routh2 #payment_route    #The ID of the route. There are no fixed rules, but it is required to be unique. It is recommended to match the service name
          uri: http://localhost:8001 # matches the routing address of the service
          predicates:
            - Path=/payment/lb/**         # Assert that the path matches the route

Look at the controller interface
The path is filled in the intercepted method interface
Last start
We type in the address field http://localhost:9527/payment/get/31
The gateway will help us forward to the corresponding address, so that we can access the data without exposing the 8001 interface

Of course, in addition to yml, we can also configure the gateway through bean
Create a new configuration class:

package com.atguigu.springcloud.config;

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author XuZhuHong
 * @CreateTime 2021/11/5 16:42
 */
@Configuration
public class GateWayConfig
{
    /**
     * A routing rule with id route name is configured,
     * When accessing address http://localhost:9527/guonei Automatically forwarded to address: http://news.baidu.com/guonei
     * @param builder
     * @return
     */
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder)
    {
        RouteLocatorBuilder.Builder routes = builder.routes();

        routes.route("path_route_atguigu", r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();

        return routes.build();

    }
    @Bean
    public RouteLocator customRouteLocator2(RouteLocatorBuilder builder)
    {
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("path_route_atguigu2", r -> r.path("/guoji").uri("http://news.baidu.com/guoji")).build();
        return routes.build();
    }
}

Then when we visit http://localhost:9527/guonei Will help us forward to http://news.baidu.com/guonei
However, when we click other addresses that are not configured, an error will be reported

12.2 optimization

We found that the above method can realize routing, but the address is written dead. It is inconvenient to call when our services increase
How to solve it? Dynamic routing through microservice name
By default, the Gateway will register the service list according to the registry,
Create a dynamic route with the micro service name on the registry as the path for forwarding, so as to realize the function of dynamic route

Just modify the yml of our router

server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #Enable the function of dynamically creating routes from the registry, and use the microservice name for routing
      routes:
        - id: payment_routh #payment_route    #The ID of the route. There are no fixed rules, but it is required to be unique. It is recommended to match the service name
          # uri: http://localhost:8001 # matches the routing address of the service
          uri: lb://Cloud payment service # matches the routing address of the service provided
          predicates:
            - Path=/payment/get/**         # Assert that the path matches the route

        - id: payment_routh2 #payment_route    #The ID of the route. There are no fixed rules, but it is required to be unique. It is recommended to match the service name
          # uri: http://localhost:8001 # matches the routing address of the service
          uri: lb://Cloud payment service # matches the routing address of the service provided
          predicates:
            - Path=/payment/lb/**         # Assert that the path matches the route

eureka:
  instance:
    hostname: cloud-gateway-service
  client: #The service provider is registered in the eureka service list
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka


It should be noted that the protocol of uri is lb, which means that the load balancing function of Gateway is enabled.

lb://serviceName is the load balancer that spring cloud gateway automatically creates for us in microservices

12.3 assertions

In our configuration attribute, we found that there is a predicate configuration, so what is this? It is assertion
In short, it is the release mismatch interception with matching conditions
What are the configurations for assertions?

12.3.1 After route assertion Factory

After route predict factory takes one parameter - date and time. Requests that occur after that date and time will be matched.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: http://example.org
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]

How to get the time string?

ZonedDateTime zbj = ZonedDateTime.now(); // Default time zone
        System.out.println(zbj);
//        ZonedDateTime zny = ZonedDateTime.now(ZoneId.of("America/New_York")); //  Gets the current time in the specified time zone
//        System.out.println(zny);

12.3.2 Before route assertion Factory

Before route predict factory takes one parameter - date and time. Requests that occur before that date and time will be matched.

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: before_route
        uri: http://example.org
        predicates:
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver]

12.3.3 Between route assertion Factory

Between route assertion Factory has two parameters, datetime1 and datetime2. The request between datetime1 and datetime2 will be matched. The actual time of the datetime2 parameter must be after datetime1.

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: between_route
        uri: http://example.org
        predicates:
        - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]

12.3.4 Cookie route assertion Factory

The cookie route assertion Factory has two parameters, cookie name and regular expression. If the request contains the secondary cookie name and the regular expression is true, it will be matched.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: http://example.org
        predicates:
        - Cookie=chocolate, ch.p

12.3.5 Header route assertion Factory

Header route assertion Factory has two parameters, header name and regular expression. If the request contains a secondary header name and the regular expression is true, it will be matched.

application.yml.

spring:
 cloud:
   gateway:
     routes:
     - id: header_route
       uri: http://example.org
       predicates:
       - Header=X-Request-Id, \d+

12.3.6 Host route assertion Factory

The Host route assertion Factory includes a parameter: host name list. Use Ant path matching rule,. As separator.
application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: http://example.org
        predicates:
        - Host=**.somehost.org,**.anotherhost.org

12.3.7 Method route assertion Factory

Method route asserts that the Factory contains only one parameter: the matching HTTP request method is required

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: http://example.org
        predicates:
        - Method=GET

All GET requests will be routed

12.3.8 Path route assertion Factory

Path route asserts that Factory has two parameters: a Spring PathMatcher expression list and an optional matchOptionalTrailingSeparator ID

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: http://example.org
        predicates:
        - Path=/foo/{segment},/bar/{segment}

For example, the requests of: / foo/1 or /foo/bar or /bar/baz will be matched

URI template variables (such as segment in the above example) will be saved in the form of Map
ServerWebExchange.getAttributes() key is
ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE.
These values will be used in GatewayFilter Factories

You can use the following methods to access these variables more easily.

Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);

String segment = uriVariables.get("segment");

12.3.9 Query route assertion Factory

Query route asserts that Factory has two parameters: required param and optional regexp

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: http://example.org
        predicates:
        - Query=baz

All that contain the request parameter baz will be matched.

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: http://example.org
        predicates:
        - Query=foo, ba.

If the request parameter contains foo parameter and the value matches ba. Expression, it will be routed, such as bar and baz

12.3.10 RemoteAddr route assertion Factory

The parameter of RemoteAddr route assertion Factory is a list of CIDR symbol (IPv4 or IPv6) strings. The minimum value is 1, for example, 192.168.0.1/16 (where 192.168.0.1 is the IP address and 16 is the subnet mask).

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: http://example.org
        predicates:
        - RemoteAddr=192.168.1.1/24

If the requested remote address is 192.168.1.10, it will be routed

Summary

 spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #Enable the function of dynamically creating routes from the registry
      routes:
        - id: payment_routh #payment_route    #The ID of the route. There are no fixed rules, but it is required to be unique. It is recommended to match the service name
          # uri: http://localhost:8001 # matches the routing address of the service
          uri: lb://Cloud payment service # matches the routing address of the service provided
          predicates:
            - Path=/payment/get/**         # Assert that the path matches the route

        - id: payment_routh2 #payment_route    #The ID of the route. There are no fixed rules, but it is required to be unique. It is recommended to match the service name
          # uri: http://localhost:8001 # matches the routing address of the service
          uri: lb://Cloud payment service # matches the routing address of the service provided



          predicates:
            - Path=/payment/lb/**         # Assert that the path matches the route
            - After=2020-02-05T15:10:03.685+08:00[Asia/Shanghai]         # Assert that the path matches the route
            #- Before=2020-02-05T15:10:03.685+08:00[Asia/Shanghai]         # Assert that the path matches the route
            #- Between=2020-02-02T17:45:06.206+08:00[Asia/Shanghai],2020-03-25T18:59:06.206+08:00[Asia/Shanghai]
            #- Cookie=username,zzyy
            #- Header=X-Request-Id, \d+  # The request header must have an X-Request-Id attribute and a regular expression with an integer value
            #- Host=**.atguigu.com
            - Method=GET
            - Query=username, \d+  # You must have a parameter name username and the value must be an integer to route

12.4 use of filter

The routing filter can be used to modify incoming HTTP requests and returned HTTP responses. The routing filter can only be used by specifying routes.

Spring Cloud Gateway has built-in multiple routing filters, which are generated by the factory class of GatewayFilter

If you use the official, you can refer to the writing method of assertion

Let's talk about customizing the global GlobalFilter filter
The custom filter must implement two interfaces, globalfilter and ordered

package com.atguigu.springcloud.filter;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Date;

@Component //Must add, must add, must add
public class MyLogGateWayFilter implements GlobalFilter,Ordered
{
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
    {
    	//exchange is similar to a servlet  
    	//chain is the next data to return. You can see return
        System.out.println("time:"+new Date()+"\t A custom global filter was implemented: "+"MyLogGateWayFilter"+"hello");
		
        String uname = exchange.getRequest().getQueryParams().getFirst("uname");
        if (uname == null) {
            System.out.println("****User name is null,Unable to log in");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder()
    {	
    	//The smaller the number, the higher the execution
        return 0;
    }
}

13 SpringCloud Config distributed configuration center

Microservice means to split the business in a single application into one sub service. The granularity of each service is relatively small, so there will be a large number of services in the system. Because each service needs the necessary configuration information to run, a centralized and dynamic configuration management facility is essential.

Spring cloud provides ConfigServer to solve this problem. Each of our microservices carries an application.yml and manages hundreds of configuration files
/(ㄒoㄒ)/~~

13.1 getting started

Code cloud warehouse will be used here
First, create a spring cloud config repository with your own account
Then write several configuration files
The file name is:

File content

config:
  info: 2021/11/6      config-prod.yml Version=1.0

Create a new configuration center module cloud-config-center-3344

<dependencies>
        <dependency>
<!--            Indicates that this is a configuration center file-->
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

yml

server:
  port: 3344

spring:
  application:
    name:  cloud-config-center #Microservice name registered into Eureka server
  cloud:
    config:
      server:
        git:
          uri: https://Gitee.com/x229827570/springcloud config / # warehouse name above
          ####search for directory
          search-paths:
            - springcloud-config
      ####Read branch
      label: master

#Service registration to eureka address
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

Don't forget to annotate the main startup class @ EnableConfigServer to open the configuration center

@SpringBootApplication
@EnableConfigServer //Open the annotation of spring cloudconfig server
public class ConfigCenterMain3344
{
    public static void main(String[] args) {
        SpringApplication.run(ConfigCenterMain3344.class, args);
    }
}

Then run when we visit http://config-3344.com:3344/master/config-dev.yml, you will see the following interface
Don't forget to map in the local host~

Connection succeeded

13.2 the server obtains information from the configuration center

Create a new module cloud-config-client-3355
Modify pom

 <dependencies>
        <dependency>
            <!--Client config The dependency of is different from that of the server -->
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

New yml
Note that the YML here is different from the previous application.yml
What needs to be created now is bootstrap.yml, so what is it?

applicaiton.yml is a user level resource configuration item
bootstrap.yml is system level, with higher priority
Spring Cloud will create a "Bootstrap Context" as the parent context of the Application Context of the spring application. During initialization, the Bootstrap Context is responsible for loading configuration properties from an external source and parsing the configuration. The two contexts share an Environment obtained from the outside.
Bootstrap properties have high priority. By default, they are not overwritten by local configuration. Bootstrap Context and Application Context have different conventions, so a bootstrap.yml file is added to ensure the separation of Bootstrap Context and Application Context configuration.
It is very important to change the application.yml file under the Client module to bootstrap.yml,
Because bootstrap.yml is loaded before application.yml. Bootstrap.yml has higher priority than application.yml

content

server:
  port: 3355

spring:
  application:
    name: config-client
  cloud:
    #Config client configuration
    config:
      label: master #Branch name
      name: config #Profile name
      profile: dev #Read the suffix name and the above three combinations: the configuration file of config-dev.yml on the master branch is read http://config-3344.com:3344/master/config-dev.yml
      uri: http://localhost:3344 # configuration center address k

#Service registration to eureka address
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka


Create startup class

@EnableEurekaClient
@SpringBootApplication
public class ConfigClientMain3355
{
    public static void main(String[] args)
    {
        SpringApplication.run(ConfigClientMain3355.class,args);
    }
}

Business class

@RestController
public class ConfigClientController
{
    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo() 
    {
        return configInfo;
    }
} 

Finally, when we start, we can find that we can get files
But when we refresh the file, we find that the client can't get the message in real time
So what

13.3 dynamic refresh of config client

Avoid restarting the client micro service 3355 every time the configuration is updated
First, introduce dependencies on the client

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Modify yml

# Exposure monitoring endpoint
management:
  endpoints:
    web:
      exposure:
        include: "*" 

Then modify the controller and add @ RefreshScope annotation on the business class

@RestController
@RefreshScope
public class ConfigClientController
{
    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo() {
        return configInfo;
    }
} 

Send to the client after the maintenance personnel modify the configuration
curl -X POST "http://localhost:3355/actuator/refresh Command to find that it has changed

The client 3355 is successfully refreshed to the latest configuration content

However, there are still problems:
How to solve it

14. Springcloud bus message bus

14.1 global notification

Install RabbitMQ before using the message bus
Erlang 21.3 and rabbitmq-server-3.7.14 are used here
Then we were in the previous
cloud-config-center-3344 configuration center server
Cloud config client 3355 / 3366 adding RabbitMQ service support for clients

<!--Add message bus RabbitMQ support-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
 

Then write the corresponding configuration in the yml configuration file
The first is the configuration of two points corresponding to 3344

server:
  port: 3344

spring:
  application:
    name:  cloud-config-center #Microservice name registered into Eureka server
  cloud:
    config:
      server:
        git:
          uri: https://Gitee.com/x229827570/springcloud config / # warehouse name above
          ####search for directory
          search-paths:
            - springcloud-config
      ####Read branch
      label: master
  #rabbitmq configuration is mainly here------------------
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

#Service registration to eureka address
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka



##rabbitmq related configuration, exposing the endpoint of bus refresh configuration
management:
  endpoints: #The endpoint of the exposed bus refresh configuration is mainly here------------------
    web:
      exposure:
        include: 'bus-refresh'

Then the yml of ports 3355 and 3366

server:
  port: 3366

spring:
  application:
    name: config-client
  cloud:
    #Config client configuration
    config:
      label: master #Branch name
      name: config #Profile name
      profile: dev #Read the suffix name and the above three combinations: the configuration file of config-dev.yml on the master branch is read
      uri: http://localhost:3344 # configuration center address k
#rabbitmq related configuration 15672 is the port of the Web management interface; 5672 is the port for MQ access
# Mainly here------------------
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

#Service registration to eureka address
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka
# Exposure monitoring endpoints are mainly here------------------
management:
  endpoints:
    web:
      exposure:
        include: "*"   # 'refresh'

Finally, we start eureka and 3344, and then start 3355 and 3366
When we modify the code on the code cloud and execute this command in cmd, we will find that all the information has been modified together

curl -X POST "http://localhost:3344/actuator/bus-refresh"

14.2 fixed point notice




Execute the following code to achieve

curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3355"

Bus refresh is the exposed refresh interface previously written in the 3344 yml configuration

15 spring cloud stream message driven

15.1 general description

It solves the problem caused by different message plug-ins
Shield the differences between the underlying message middleware, reduce the switching cost, and unify the programming model of message
Why use him

For example, we use RabbitMQ and Kafka. Due to the different architectures of the two message oriented middleware,
For example, RabbitMQ has exchange and kafka has Topic and Partitions,

The differences of these middleware lead to some problems in our actual project development. If we use one of the two message queues and the business requirements behind it, I want to migrate to another message queue. At this time, it is undoubtedly disastrous. A lot of things have to be pushed down and redone because it is coupled with our system, At this time, springcloud Stream provides us with a decoupling method.

Common notes are as follows

15.2 message sending operation

Before performing these operations, we must first ensure that the RabbitMQ environment is OK
Create a module cloud stream rabbitmq provider8801 as a message sending module for producers
pom

    <dependencies>
        <!--Because it's used here rabbitmq So we need to introduce rabbit Something-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <!--Basic configuration-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

yml its binder attribute may be red, and it can still run regardless

server:
  port: 8801

spring:
  application:
    name: cloud-stream-provider
  cloud:
    stream:
      binders: # Configure the service information of rabbitmq to be bound here;
        defaultRabbit: # Represents the name of the definition, which is used for binding integration
          type: rabbit # The message component type used here is rabbitmq
          environment: # Set the environment configuration related to rabbitmq
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
      bindings: # Integration of services
        output: # output represents the sender of the message. This name is the name of a channel 
          destination: studyExchange # Represents the Exchange name definition to use
          content-type: application/json # Set the message type, json this time, and "text/plain" for text
          binder: defaultRabbit # Set the specific settings of the message service to be bound

eureka:
  client: # Configure Eureka registration on the client
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    lease-renewal-interval-in-seconds: 2 # Set the heartbeat interval (30 seconds by default)
    lease-expiration-duration-in-seconds: 5 # If the interval of 5 seconds is exceeded now (the default is 90 seconds)
    instance-id: send-8801.com  # Displays the host name in the information list
    prefer-ip-address: true     # The access path becomes an IP address

Main start

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

A simple service interface

public interface IMessageProvider{
    public String send() ;
}

His implementation class should pay attention not to introduce the wrong package, and the call can be implemented without service annotation

package com.atguigu.springcloud.service.impl;

import com.atguigu.springcloud.service.IMessageProvider;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.MessageBuilder;

import javax.annotation.Resource;
import java.util.UUID;

/**
 * @Author XuZhuHong
 * @CreateTime 2021/11/6 18:05
 */
@EnableBinding(Source.class) //Source indicates the sender of the message
public class MessageProviderImpl implements IMessageProvider {

    @Resource
    private MessageChannel output;  //Components required to send messages

    @Override
    public String send() {
        String serial = UUID.randomUUID().toString();
        //Put the message into the message queue
        output.send(MessageBuilder.withPayload(serial).build());
        System.out.println(serial);
        return serial;
    }
}

Simple controller interface

@RestController
public class SendMessageController
{
    @Resource
    private IMessageProvider messageProvider;

    @GetMapping(value = "/sendMessage")
    public String sendMessage()
    {
        return messageProvider.send();
    }
}

When we successfully started this service
You can add one more channel in the visualization page of robbinMQ

This channel is what we set up before

When we refresh crazily, we can see the crest map in the visual interface

15.3 message reception

Create a cloud stream rabbitmq consumer 8802

   <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--Basic configuration-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

yml

server:
  port: 8802

spring:
  application:
    name: cloud-stream-consumer
  cloud:
    stream:
      binders: # Configure the service information of rabbitmq to be bound here;
        defaultRabbit: # Represents the name of the definition, which is used for binding integration
          type: rabbit # Message component type
          environment: # Set the environment configuration related to rabbitmq
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
      bindings: # Integration of services
        input: # input indicates that it is the receiving port. This name is the name of a channel
          destination: studyExchange # Indicates the Exchange name to use to define the channel
          content-type: application/json # Set the message type. This time it is an object json. If it is text, set the data received by "text/plain"
          binder: defaultRabbit # Set the specific settings of the message service to be bound

eureka:
  client: # Configure Eureka registration on the client
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    lease-renewal-interval-in-seconds: 2 # Set the heartbeat interval (30 seconds by default)
    lease-expiration-duration-in-seconds: 5 # If the interval of 5 seconds is exceeded now (the default is 90 seconds)
    instance-id: receive-8802.com  # Displays the host name in the information list
    prefer-ip-address: true     # The access path becomes an IP address

Main startup class

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

The controller class needs to be annotated with @ EnableBinding(Sink.class) to indicate that it is enabled and is the receiver

@Controller
@EnableBinding(Sink.class) //EnableBinding enables this message binding. sink indicates that this is the receiver
public class ReceiveMessageListener {
    @Value("${server.port}")
    private String serverPort;

    @StreamListener(Sink.INPUT)  //Sink.INPUT indicates that this is the receiving method
    //A simple receiving method, in which the receiving method parameters are fixed
    public void input(Message<String> message)
    {
        System.out.println("Consumer 1,------->Received message:" + message.getPayload()+"\t port: "+serverPort);
    }
}

So when we start this class
Re access message sender http://localhost:8801/sendMessage
You'll see the news on our recipient's side

15.4 group consumption and persistence

When we simulate 8802 port 8803 to run, we find that when sending a message, both consumers will read the message
How to solve the problem of repeated consumption

When microservice applications are placed in the same group, it can ensure that messages will only be consumed once by one of them.
Different groups can be consumed. There will be competition in the same group, and only one of them can be consumed.

In fact, it is very simple to add a group. If the two groups are the same, this problem can be solved

In addition, adding packets can also effectively prevent message loss (that is, when the message sender sends a message and there is no receiver, we will not receive the message when we start the receiver without packets, but the receiver with groups can receive it)

Keywords: Spring Cloud Cloud Native

Added by peeps on Sat, 06 Nov 2021 15:54:18 +0200