Categories
Uncategorized

Spring Cloud Alibaba | Gateway Gateway-based dynamic routing Nacos

Spring Cloud Alibaba | Gateway Gateway-based dynamic routing Nacos

Benpian related to combat the Spring version:

SpringBoot:2.1.7.RELEASE

Spring Cloud:Greenwich.SR2

Spring CLoud Alibaba:2.1.0.RELEASE

Previous articles we introduced the “Nacos service registration and discovery” and “Nacos configuration management,” have not seen the little friends quickly take a look, this article is based on a real basis of these two articles.

Background

In Spring Cloud micro-service system, commonly used services gateway has open source Netflix, Zuul, as well as their own team of open source Spring Cloud Spring Cloud Gateway, which NetFlix company Zuul open source version has iterated to 2.x, but not Spring Cloud integration, integration of the current Spring Cloud Spring Cloud Zuul or Zuul1.x, this edition is based on Servlet Zuul building, using the blocking scheme is a multi-threaded program, a thread that is processed once the connection request, in this way inside a serious delay, malfunction of equipment in many cases will lead to increased survival and increase the thread of connection to happen. Spring Cloud Spring Cloud Gateway own open source is based on Spring Webflux to build, Spring Webflux there is a new non-clogging functional Reactive Web framework that can be used to build asynchronous, non-blocking, event-driven service, telescopic in terms of performance is very good. Use non-blocking API, Websockets be supported, and because of its tight integration with Spring, will get better development experience.

This paper will be based Gateway Services Gateway describes how to use configuration function Nacos to implement dynamic routing service gateway.

Implementation

Before we begin to introduce specific ways:

    Routing information is no longer configured in the configuration file, routing information configured in Nacos configuration.

    Spring Cloud Gateway service gateway open to listen, listen modify Nacos profile.

    Nacos profile Once changed, the Spring Cloud Gateway refresh their routing information.

Preparing the Environment

First, you need to prepare a Nacos service, here is my version Nacos v1.1.3 used, if the service is not configured Nacos students, please refer to the previous article “Study Nacos service center”

Combat engineering

Create Project gateway-nacos-config, engineering rely pom.xml as follows:



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.7.RELEASE
         
    
    com.springcloud.alibaba
    gateway-nacos-config
    0.0.1-SNAPSHOT
    gateway-nacos-config
    gateway-nacos-config

    
        UTF-8
        UTF-8
        1.8
        Greenwich.SR2
        2.1.0.RELEASE
    

    
        
            org.springframework.boot
            spring-boot-starter-actuator
        
        
            org.springframework.boot
            spring-boot-starter-webflux
        
        
            org.springframework.cloud
            spring-cloud-starter-gateway
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        

        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
            io.projectreactor
            reactor-test
            test
        
    

    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                ${spring-cloud.version}
                pom
                import
            
            
                com.alibaba.cloud
                spring-cloud-alibaba-dependencies
                ${spring-cloud-alibaba.version}
                pom
                import
            
        
    

    
        
            spring-milestones
            Spring Milestones
            https://repo.spring.io/libs-milestone
            
                false
            
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


    When using Spring Cloud Alibaba assembly, in the need to configure the spring-cloud-alibaba-dependencies, which manages the version dependency Spring Cloud Alibaba assembly.

Profile application.yml as follows:

server:
  port: 8080
spring:
  application:
    name: spring-cloud-gateway-server
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.44.129:8848
management:
  endpoints:
    web:
      exposure:
        include: '*'

    spring.cloud.nacos.discovery.server-addr: configured Nacos service address in the form ip: port

Next, enter the core part of the configuration Spring Cloud Gateway dynamic routing, where the need to implement an event Spring provides a push interfaces ApplicationEventPublisherAware, code is as follows:

@Component
public class DynamicRoutingConfig implements ApplicationEventPublisherAware {

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

    private static final String DATA_ID = "zuul-refresh-dev.json";
    private static final String Group = "DEFAULT_GROUP";

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher applicationEventPublisher;

    @Bean
    public void refreshRouting() throws NacosException {
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, "192.168.44.129:8848");
        properties.put(PropertyKeyConst.NAMESPACE, "8282c713-da90-486a-8438-2a5a212ef44f");
        ConfigService configService = NacosFactory.createConfigService(properties);
        configService.addListener(DATA_ID, Group, new Listener() {
            @Override
            public Executor getExecutor() {
                return null;
            }

            @Override
            public void receiveConfigInfo(String configInfo) {
                logger.info(configInfo);

                boolean refreshGatewayRoute = JSONObject.parseObject(configInfo).getBoolean("refreshGatewayRoute");

                if (refreshGatewayRoute) {
                    List list = JSON.parseArray(JSONObject.parseObject(configInfo).getString("routeList")).toJavaList(RouteEntity.class);

                    for (RouteEntity route : list) {
                        update(assembleRouteDefinition(route));
                    }
                } else {
                    logger.info("路由未发生变更");
                }


            }
        });
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    /**
     * 路由更新
     * @param routeDefinition
     * @return
     */
    public void update(RouteDefinition routeDefinition){

        try {
            this.routeDefinitionWriter.delete(Mono.just(routeDefinition.getId()));
            logger.info("路由更新成功");
        }catch (Exception e){
            logger.error(e.getMessage(), e);
        }

        try {
            routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
            this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
            logger.info("路由更新成功");
        }catch (Exception e){
            logger.error(e.getMessage(), e);
        }
    }

    public RouteDefinition assembleRouteDefinition(RouteEntity routeEntity) {

        RouteDefinition definition = new RouteDefinition();

        // ID
        definition.setId(routeEntity.getId());

        // Predicates
        List pdList = new ArrayList<>();
        for (PredicateEntity predicateEntity: routeEntity.getPredicates()) {
            PredicateDefinition predicateDefinition = new PredicateDefinition();
            predicateDefinition.setArgs(predicateEntity.getArgs());
            predicateDefinition.setName(predicateEntity.getName());
            pdList.add(predicateDefinition);
        }
        definition.setPredicates(pdList);

        // Filters
        List fdList = new ArrayList<>();
        for (FilterEntity filterEntity: routeEntity.getFilters()) {
            FilterDefinition filterDefinition = new FilterDefinition();
            filterDefinition.setArgs(filterEntity.getArgs());
            filterDefinition.setName(filterEntity.getName());
            fdList.add(filterDefinition);
        }
        definition.setFilters(fdList);

        // URI
        URI uri = UriComponentsBuilder.fromUriString(routeEntity.getUri()).build().toUri();
        definition.setUri(uri);

        return definition;
    }
}

Here mainly introduce refreshRouting () This method, which is mainly responsible for monitoring configuration changes Nacos, where the first parameter to build a ConfigService, then use ConfigService open a listener, and refresh routing information in the process of listening in.

FIG Nacos configuration:

{
    "refreshGatewayRoute":false,
    "routeList":[
        {
            "id":"github_route",
            "predicates":[
                {
                    "name":"Path",
                    "args":{
                        "_genkey_0":"/meteor1993"
                    }
                }
            ],
            "filters":[

            ],
            "uri":"https://github.com",
            "order":0
        }
    ]
}

Select the configuration format JSON, Data ID and Group and program configuration consistent attention, I am here to configure the program namespace, if you use the default namespace, you can not configure.

Here is configured with a routing / meteor1993, direct access to this route will have access to the author’s Github repository.

The remaining part of the code here is not demonstrated, the code has been uploaded to the warehouse, needy students can access on their own.

test

Start project, then there is no routing information, open the browser to access: http: // localhost: 8080 / meteor1993, the page returns a 404 error message as:

Also, you can access the link: http: // localhost: 8080 / actuator / gateway / routes, see the following print:

[]

Open Nacos Server-side UI interface, select the monitoring query, select the namespace for the springclouddev column, enter DATA_ID as zuul-refresh-dev.json and the Group for the DEFAULT_GROUP, click the query, you can see we start engineering gateway-nacos-config is Nacos Server listens end, as shown:

Here is the author’s local ip: 192.168.44.1. Normal listening, this time, we modify the configuration just created, which will modify the refreshGatewayRoute is true, as follows:

{"refreshGatewayRoute": true, "routeList":[{"id":"github_route","predicates":[{"name":"Path","args":{"_genkey_0":"/meteor1993"}}],"filters":[],"uri":"https://github.com","order":0}]}

Click Publish, you can see the project gateway-nacos-config console print log is as follows:

2019-09-02 22:09:49.254  INFO 8056 --- [38-2a5a212ef44f] c.s.a.g.config.DynamicRoutingConfig      : {
    "refreshGatewayRoute":true,
    "routeList":[
        {
            "id":"github_route",
            "predicates":[
                {
                    "name":"Path",
                    "args":{
                        "_genkey_0":"/meteor1993"
                    }
                }
            ],
            "filters":[

            ],
            "uri":"https://github.com",
            "order":0
        }
    ]
}
2019-09-02 22:09:49.268  INFO 8056 --- [38-2a5a212ef44f] c.s.a.g.config.DynamicRoutingConfig      : 路由更新成功

At this time, our engineering route gateway-nacos-config has been updated successfully, the access path: http: // localhost: 8080 / actuator / gateway / routes, see the following print:

[{"route_id":"github_route","route_definition":{"id":"github_route","predicates":[{"name":"Path","args":{"_genkey_0":"/meteor1993"}}],"filters":[],"uri":"https://github.com","order":0},"order":0}]

Once again, we access the link in your browser: http: // localhost: 8080 / meteor1993, you can see the page properly routed to the Github repository, as shown:

to sum up

So far, Nacos dynamic routing gateway will introduce over, the main use of the service gateway side listener Nacos configuration change capability to enable dynamic service gateway routing configuration refresh Similarly, we can also use the service gateway Zuul be implemented based on dynamic routing capabilities of Nacos.

Based on this idea, we can use the configuration center to implement dynamic routing gateway, instead of using the service gateway comes with its own configuration file so that every time the routing information is changed, without changing the configuration file and then restart the service.

Currently on the market use more open source configuration Ctrip center of Apollo, as well as serving gateway Spring Cloud Zuul, the next article, we describe how to use Apollo to implement dynamic routing Spring Cloud Zuul’s.

Sample Code

Github- Sample Code

Gitee- Sample Code

Leave a Reply