Spring Cloud Gateway practice 2: more routing configuration methods

Welcome to my GitHub

https://github.com/zq2599/blog_demos

Content: classification and summary of all original articles and supporting source code, involving Java, Docker, Kubernetes, DevOPS, etc;

Overview of this article

  • This article is the second in the Spring Cloud Gateway practical combat series. Through the previous article, we learned that the core of Spring Cloud Gateway is routing configuration, and then a route is configured in the local application.yml. However, this way of modifying the local configuration file is inflexible and may not meet the flexible business requirements. Therefore, The purpose of this article is to find out other configuration methods other than local configuration to meet various actual needs;
  • In general, the following three methods are commonly used:
  • The target address supports the service name (replacing the previous IP + port);
  • Support configuration on nacos;
  • Support code writing configuration;
  • In addition, there is a more flexible configuration method: < font color = "blue" > dynamic agent < / font >, which will be described in a separate article because it involves a lot of code

Source download

  • The complete source code in this actual combat can be downloaded from GitHub. The address and link information are shown in the table below( https://github.com/zq2599/blo...):
namelinkremarks
Project Home https://github.com/zq2599/blo...The project is on the GitHub home page
git warehouse address (https)https://github.com/zq2599/blo...The warehouse address of the source code of the project, https protocol
git warehouse address (ssh)git@github.com:zq2599/blog_demos.gitThe project source code warehouse address, ssh protocol
  • There are multiple folders in this git project. The source code of this article is in the < font color = "blue" > spring cloud tutorials < / font > folder, as shown in the red box below:

preparation

  • A little more preparation needs to be done before the official start. In the whole Spring Cloud Gateway practice series, all requests will finally be routed to the < font color = "blue" > provider Hello < / font > Web. At present, the service has only one web interface < font color = "blue" > / hello / str < / font >. Now let's add another one to it, which will be used in the later practice
  • The newly added web interface comes from LBTest.java, which is very simple:
package com.bolingcavalry.provider.controller;

import com.bolingcavalry.common.Constants;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;

@RestController
@RequestMapping("/lbtest")
public class LBTest {

    private String dateStr(){
        return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());
    }

    /**
     * Return string type
     * @return
     */
    @GetMapping("/str")
    public String helloStr() {
        return Constants.LB_PREFIX + ", " + dateStr();
    }
}
  • The < font color = "blue" > constants.lb_prefix < / font > in the above code comes from the sub project < font color = "red" > common < / font >:
package com.bolingcavalry.common;

public interface Constants {
    String HELLO_PREFIX = "Hello World";
    String LB_PREFIX = "Load balance";
}
  • After writing the code, make sure that nacos is started
  • After the < font color = "blue" > provider Hello < / font > project is started successfully, go to see nacos and confirm that it has been registered:

  • Ready to start the actual combat

The destination address supports the service name (replacing the previous IP + port)

  • Let's start with the simplest. Let's look at the routing configuration above, as shown in the red box below. The target address is IP + port:

  • After playing Spring Cloud, you naturally see the problem: no registration is found. Indeed, it is inappropriate to write the address and port in the configuration file. Let's solve this problem first;
  • A new sub project named < font color = "blue" > gateway by loadbalance < / font > is added. The dependencies in pom.xml are as follows. It can be seen that the focus is < font color = "red" > spring cloud starter loadbalance < / font >:
<dependencies>
        <dependency>
            <groupId>com.bolingcavalry</groupId>
            <artifactId>common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Routing policy usage lb The way is that this dependency must have -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <!--nacos:Registration Center-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>
  • The code of the startup class is omitted (as before)
  • The configuration information is as follows. The key point is that the uri value < font color = "red" > LB: / / provider Hello < / font >, with the prefix < font color = "blue" > LB: < / font >, followed by < font color = "blue" > provider hello < / font > is the service name registered in nacos:
server:
  #Service port
  port: 8085
spring:
  application:
    name: gateway-by-loadbalance
  cloud:
    nacos:
      # Configuration of registry
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
        - id: path_route_lb
          uri: lb://provider-hello
          predicates:
          - Path=/lbtest/**
  • Unit test class:
package com.bolingcavalry.gateway;

import com.bolingcavalry.common.Constants;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.junit.jupiter.api.Assertions.assertTrue;

@SpringBootTest
@ExtendWith(SpringExtension.class)
@AutoConfigureWebTestClient
public class HelloTest {

    @Autowired
    private WebTestClient webClient;

    @Test
    void testLoadBalance() {
        webClient.get()
                .uri("/lbtest/str")
                .accept(MediaType.APPLICATION_JSON)
                .exchange()
                // Verification status
                .expectStatus().isOk()
                // Verify the result. Note that the result is in string format
                .expectBody(String.class).consumeWith(result  -> assertTrue(result.getResponseBody().contains(Constants.LB_PREFIX)));
    }
}
  • Run the unit test. It can be seen that the above configuration can accurately find the service through the prefix < font color = "blue" > LB: < / font >:

Support configuration on nacos

  • There is a problem in writing all configuration information in application.yml: remote configuration is not possible, which is inconvenient in scenarios with a large number of applications. Fortunately, nacos provides the ability of remote configuration. After the application is started, you can get your own configuration information from nacos. Let's try
  • A new sub project named < font color = "blue" > gateway Nacos config < / font > is added. The dependencies in pom.xml are as follows. Please pay attention to the Chinese notes inside. Each indicates the role of each dependency:
<dependencies>
        <dependency>
            <groupId>com.bolingcavalry</groupId>
            <artifactId>common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- use bootstrap.yml This dependence must have -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        <!-- Routing policy usage lb The way is that this dependency must have -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <!--nacos:Configuration center-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--nacos:Registration Center-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>
  • The local configuration file < font color = "blue" > bootstrap. YML < / font >, which is very simple, is the address and remote configuration information of nacos:
spring:
  application:
    name: gateway-nacos-config
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yml
        group: DEFAULT_GROUP
  • Next, add a configuration file to nacos, as shown in the red box below:

  • Add a configuration. The points to note are as follows (the text of the configuration information will be given later for easy replication):

  • The complete configuration information in the figure above is as follows:
server:
  port: 8083
spring:
  cloud:
    gateway:
      routes:
        - id: path_route_addr
          uri: http://127.0.0.1:8082
          predicates:
          - Path=/hello/**
        - id: path_route_lb
          uri: lb://provider-hello
          predicates:
          - Path=/lbtest/**
  • The two test methods in the test class are as follows, which are no different from the previous ones:
@Test
    void testHelloPredicates() {
        webClient.get()
                .uri("/hello/str")
                .accept(MediaType.APPLICATION_JSON)
                .exchange()
                // Verification status
                .expectStatus().isOk()
                // Verify the result. Note that the result is in string format
                .expectBody(String.class).consumeWith(result  -> assertTrue(result.getResponseBody().contains(Constants.HELLO_PREFIX)));
    }

    @Test
    void testLoadBalance() {
        webClient.get()
                .uri("/lbtest/str")
                .accept(MediaType.APPLICATION_JSON)
                .exchange()
                // Verification status
                .expectStatus().isOk()
                // Verify the result. Note that the result is in string format
                .expectBody(String.class).consumeWith(result  -> assertTrue(result.getResponseBody().contains(Constants.LB_PREFIX)));
    }
  • Run the unit test class and pass the test, which proves that the configuration file obtained from nacos is successful:

Write code configuration

  • In the previous examples, the routing information is written in the configuration file. In fact, there is another way: write code to configure the routing. You can write your own code to configure it, which is more flexible
  • Add a sub project named < font color = "blue" > gateway by code < / font >, and its pom.xml file can refer to the previous project
  • Next, the focus of this example is to add a RouteLocator type bean in the configuration class. You can add a route through the following code:
package com.bolingcavalry.gateway.cofig;

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;

@Configuration
public class RouteConfig {

    @Bean
    public RouteLocator customizeRoute(RouteLocatorBuilder builder) {
        return builder
                .routes()
                .route(
                            // The first parameter is the unique identity of the route
                        "path_route_lb",
                            // The second parameter is a lambda implementation,
                            // The matching conditions are set to match according to the request path and the forwarding address,
                            // Note that lb: / / indicates that this is a service name, which should be from
                            r -> r.path("/lbtest/**").uri("lb://provider-hello")
                )
                .build();
    }
}
  • Only one route is configured for the above code, and the other is in the configuration file, so you can verify whether the code and the configuration file can take effect at the same time:
server:
  #Service port
  port: 8084
spring:
  application:
    name: gateway-by-code
  cloud:
    nacos:
      discovery:
        # nacos service address
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
        - id: path_route_addr
          uri: http://127.0.0.1:8082
          predicates:
          - Path=/hello/**
  • The test class is as like as two peas in the previous project, and it does not occupy space. It is still the two test method <font color= "blue" >testHelloPredicates</font> and <font color= "blue" >testLoadBalance</font>.
  • The execution unit test can be passed successfully, which proves that there is no problem with the code configuration Routing:

  • So far, we have tried examples of load balancing, nacos configuration and code configuration. Together, they will bring great convenience to the configuration of the actual living environment. I hope we can give you some reference

Defects and Solutions

  • Although there are many configuration methods mentioned above, there is a common problem: after the configuration changes, the Gateway application needs to be restarted to take effect, which is difficult to accept in the continuous production environment
  • In order to make the latest routing configuration take effect without restarting the Gateway application, let's explore how < font color = "blue" > dynamic routing < / font > is implemented in the next article

You're not alone. Xinchen's original accompanies you all the way

  1. Java series
  2. Spring collection
  3. Docker series
  4. kubernetes series
  5. Database + middleware series
  6. DevOps series

Welcome to the official account: programmer Xin Chen

Wechat search "programmer Xinchen", I'm Xinchen, looking forward to traveling with you in the Java World
https://github.com/zq2599/blog_demos

Keywords: cloud computing

Added by Paingiver on Tue, 09 Nov 2021 02:10:32 +0200