Spring Cloud gateway gateway four dynamic routing

Micro current level of service so popular, if you can not learn a micro-service framework technology. How can promotion and pay rise, increasing the chips resume? spring cloud and Dubbo to learn alone. That there is no time? No energy? To learn both a framework? The Spring Cloud alibaba you only need to learn a'll have two kinds of micro-technology service management framework. why not? Come on! Sao ape years

Before the zuul we talk about it. How to get dynamic routing. As the son of pro-exist Spring Cloud gateway could not support dynamic routing. Preliminary Today we look at the dynamic routing gateway.

Demand front. In the understanding of the dynamic routing. You might be able to expect our data to be stored in a database or redis them. There are also stored in the entity classes.

Thinking:

配置中心刷新routes配置信息。路由信息刷新改变。利用事件发布,利用配置中心完成动态刷新路由。本次改造我们使用自定义存储方式达到手动触发动态路由

InMemoryRouteDefinitionRepository 默认使用。这个类就是把握们当前的所有的路由routes 存储在内存当中。当服务重启或者刷新,内存就不复存在。ps: 因为本项目是用nacos 注册中心也是配置中心。可以存储在nacos 配置中心里面。
RouteDefinitionRepository 接口是InMemoryRouteDefinitionRepository 是它的接口类 继承了 RouteDefinitionLocator 、RouteDefinitionWriter俩个接口。

RouteDefinitionLocator Interface

file

RouteDefinitionWriter used to implement add and delete routes.

Thinking:

基于这个原则我们在动态添加或者删除路由的时候,就可以根据这个接口实现去满足我们动态的控制路由规则。

RouteDefinitionRepository This interface has become the key point we have to re-routing is actually based on the dynamic interface to achieve

Entity class

package com.xian.cloud.model;

import lombok.Data;

/**
 * @Author: xlr
 * @Date: Created in 5:10 PM 2019/9/29
 */
@Data
public class GatewayRoutesEntity {

    private Long id;

    private String serviceId;

    private String uri;

    private String predicates;

    private String filters;

}

GatewayRoutesService Interface

package com.xian.cloud.service;

import com.xian.cloud.model.GatewayRoutesEntity;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;

import java.util.List;

/**
 * <Description>
 *
 * @author [email protected]
 * @version 1.0
 * @createDate 2019/11/08 16:08
 */
public interface GatewayRoutesService {

    List<GatewayRoutesEntity> findAll() throws Exception;

    String loadRouteDefinition() throws Exception;

    GatewayRoutesEntity save(GatewayRoutesEntity gatewayDefine) throws Exception;

    void deleteById(String id) throws Exception;

    boolean existsById(String id)throws Exception;

    List<PredicateDefinition> getPredicateDefinition(String predicates) ;

    List<FilterDefinition> getFilterDefinition(String filters) ;

}

GatewayRoutesService implementation class

package com.xian.cloud.service.impl;

import com.alibaba.fastjson.JSON;
import com.xian.cloud.model.GatewayRoutesEntity;
import com.xian.cloud.service.GatewayRoutesService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.List;

/**
 * <Description>
 *
 * @author [email protected]
 * @version 1.0
 * @createDate 2019/11/08 16:09
 */
@Service
@Slf4j
public class GatewayRoutesServiceImpl implements GatewayRoutesService {

    public static final String GATEWAY_DEFINE_LIST_KEY = "gateway_routes_list_key";

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher publisher;

    @Override
    public List <GatewayRoutesEntity> findAll() throws Exception {

        Long size = redisTemplate.opsForList().size( GATEWAY_DEFINE_LIST_KEY );
        List<GatewayRoutesEntity> list = redisTemplate.opsForList().range( GATEWAY_DEFINE_LIST_KEY, 0, size );
        return list;
    }

    @Override
    public String loadRouteDefinition() {
        try {
            List <GatewayRoutesEntity> gatewayDefineServiceAll = findAll();
            if (gatewayDefineServiceAll == null) {
                return "none route defined";
            }
            for (GatewayRoutesEntity gatewayDefine : gatewayDefineServiceAll) {
                RouteDefinition definition = new RouteDefinition();
                definition.setId( gatewayDefine.getServiceId() );
                definition.setUri( new URI( gatewayDefine.getUri() ) );
                List <PredicateDefinition> predicateDefinitions = getPredicateDefinition(gatewayDefine.getPredicates());
                if (predicateDefinitions != null) {
                    definition.setPredicates( predicateDefinitions );
                }
                List <FilterDefinition> filterDefinitions = getFilterDefinition(gatewayDefine.getFilters());
                if (filterDefinitions != null) {
                    definition.setFilters( filterDefinitions );
                }
                routeDefinitionWriter.save( Mono.just( definition ) ).subscribe();
                publisher.publishEvent( new RefreshRoutesEvent( this ) );
            }
            return "success";
        } catch (Exception e) {
            e.printStackTrace();
            return "failure";
        }
    }

    /**
     * 获取所有的 自定义路由规则
     * @param gatewayDefine
     * @return
     * @throws Exception
     */
    @Override
    public GatewayRoutesEntity save(GatewayRoutesEntity gatewayDefine) throws Exception {
        log.info( "save RouteDefinition : {}",gatewayDefine );
        redisTemplate.opsForList().rightPush(  GATEWAY_DEFINE_LIST_KEY, gatewayDefine );
        return gatewayDefine;
    }

    @Override
    public void deleteById(String id) throws Exception {
        List <GatewayRoutesEntity> all = findAll();
        for (GatewayRoutesEntity gatewayDefine : all) {
            if(gatewayDefine.getServiceId().equals( id )){
                redisTemplate.opsForList().remove( GATEWAY_DEFINE_LIST_KEY,0, gatewayDefine);
            }
        }
    }

    @Override
    public boolean existsById(String id) throws Exception {
        List <GatewayRoutesEntity> all = findAll();
        for (GatewayRoutesEntity gatewayDefine : all) {
            if(gatewayDefine.getServiceId().equals( id )){
                return true;
            }
        }
        return false;
    }

    @Override
    public List<PredicateDefinition> getPredicateDefinition(String predicates) {
        if ( StringUtils.isNotBlank( predicates )) {
            List<PredicateDefinition> predicateDefinitionList = JSON.parseArray(predicates, PredicateDefinition.class);
            return predicateDefinitionList;
        } else {
            return null;
        }
    }
    @Override
    public List<FilterDefinition> getFilterDefinition(String filters) {
        if (StringUtils.isNotBlank( filters )) {
            List<FilterDefinition> filterDefinitionList = JSON.parseArray(filters, FilterDefinition.class);
            return filterDefinitionList;
        } else {
            return null;
        }
    }
}

Then we conduct RouteDefinitionLocator, RouteDefinitionWriter both a declaration in the interface configuration file

package com.xian.cloud.config;

import com.xian.cloud.repository.GatewayRoutesRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * <Description> 动态更新路由
 *
 * @author [email protected]
 * @version 1.0
 * @createDate 2019/11/08 17:12
 */
@Configuration
@Slf4j
public class GatewayRoutesDefinitionConfig {


    @Bean
    RouteDefinitionLocator routeDefinitionLocator(){
        return new GatewayRoutesRepository();
    }
        
    @Bean
    @Primary
    RouteDefinitionWriter routeDefinitionWriter(){
        return new GatewayRoutesRepository();
    }
}

RefreshRoutesEvent events publishing refresh routes event notification gateway. This event is the gateway event.

package com.xian.cloud.event;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;

/**
 * <Description>
 *
 * @author [email protected]
 * @version 1.0
 * @createDate 2019/11/08 17:20
 */
@Component
@Slf4j
public class RefreshRouteService implements ApplicationEventPublisherAware {

    private ApplicationEventPublisher publisher;

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

    /**
     * 刷新路由表
     */
    public void refreshRoutes() {
        publisher.publishEvent(new RefreshRoutesEvent(this));
    }
}

Then we are still a manual trigger interface, create GatewayRoutesController

package com.xian.cloud.controller;

import com.xian.cloud.event.RefreshRouteService;
import com.xian.cloud.model.RestResult;
import com.xian.cloud.model.RestResultBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * <Description>
 *
 * @author [email protected]
 * @version 1.0
 * @createDate 2019/11/08 17:18
 */
@RestController
@RequestMapping("/gateway")

public class GatewayRoutesController {

    @Autowired
    private RefreshRouteService refreshRouteService;

    @GetMapping("/refreshRoutes")
    public RestResult refreshRoutes(){
        refreshRouteService.refreshRoutes();
        return RestResultBuilder.builder().success().build();
    }
}

So far, all the code is complete.

Start Service

In fact, there is a very simple and direct wording. Reference to redefine Spring Cloud combat the wording.

Create an event to increase class DynamicRouteServiceImpl

package com.xian.cloud.event;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

/**
 * <Description>
 *
 * @author [email protected]
 * @version 1.0
 * @createDate 2019/11/09 10:40
 */
@Slf4j
@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {

    @Qualifier("routeDefinitionRepositor")
    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher publisher;

    /**
     * 添加路由实体类
     * @param definition
     * @return
     */
    public boolean add(RouteDefinition definition){
        routeDefinitionWriter.save((Mono<RouteDefinition>) Mono.just(definition).subscribe());
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return true;
    }

    /**
     *
     * @param definition 路由实体类
     * @return
     */
    public boolean update(RouteDefinition definition){
        try {
            routeDefinitionWriter.delete(Mono.just(definition.getId()));
        }catch (Exception e){
            log.error("update 失败。没有找到对应的路由ID :{}",definition.getId());
        }

        routeDefinitionWriter.save((Mono<RouteDefinition>) (Mono.just(definition)).subscribe());
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return true;
    }

    /**
     * serviceId
     * @param id
     * @return
     */
    public boolean del(String id){
        routeDefinitionWriter.delete(Mono.just(id));
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return true;
    }

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

Add three methods to modify controller

package com.xian.cloud.controller;

import com.xian.cloud.event.DynamicRouteServiceImpl;
import com.xian.cloud.event.RefreshRouteService;
import com.xian.cloud.model.RestResult;
import com.xian.cloud.model.RestResultBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.web.bind.annotation.*;

/**
 * <Description>
 *
 * @author [email protected]
 * @version 1.0
 * @createDate 2019/11/08 17:18
 */
@RestController
@RequestMapping("/gateway")
public class GatewayRoutesController {

    @Autowired
    private RefreshRouteService refreshRouteService;

    @Autowired
    private DynamicRouteServiceImpl dynamicRouteService;

    @GetMapping("/refreshRoutes")
    public RestResult refreshRoutes(){
        refreshRouteService.refreshRoutes();
        return RestResultBuilder.builder().success().build();
    }

    /**
     *
     * @param definition
     * @return
     */
    @RequestMapping(value = "routes/add",method = RequestMethod.POST)
    public RestResult add(@RequestBody RouteDefinition definition){
        boolean flag = dynamicRouteService.add(definition);
        if(flag){
            return RestResultBuilder.builder().success().build();
        }
        return RestResultBuilder.builder().failure().build();
    }

    /**
     *
     * @param definition
     * @return
     */
    @RequestMapping(value = "routes/update",method = RequestMethod.POST)
    public RestResult update(@RequestBody RouteDefinition definition){
        boolean flag = dynamicRouteService.add(definition);
        if(flag){
            return RestResultBuilder.builder().success().build();
        }
        return RestResultBuilder.builder().failure().build();
    }

    /**
     *
     * @param serviceId
     * @return
     */
    @RequestMapping(value = "routes/del",method = RequestMethod.POST)
    public RestResult update(@RequestParam("serviceId") String serviceId){
        boolean flag = dynamicRouteService.del(serviceId);
        if(flag){
            return RestResultBuilder.builder().success().build();
        }
        return RestResultBuilder.builder().failure().build();
    }
}

Additions and deletions. Three interfaces of external exposure.

These are dynamic refresh the routing gateway.

Think

Dynamic refresh to meet us in the service management to facilitate operation and maintenance. But because this whole nacos distribution center used to do. Consider the cost of doing so. Dynamic refresh is not really necessary to do so. Configuration can then refresh in the configuration center. You can trigger overall refresh route. If you need to build your own operation and maintenance center. It has its own management system enables dynamic routing.

Taken reference spring cloud official documents

Sample Code Address

Nacos server address http://47.99.209.72:8848/nacos

Past addresses spring cloud article addresses

spring cloud alibaba Profile

Spring Cloud Alibaba (nacos registration center set up)

Spring Cloud Alibaba use nacos registry

Spring Cloud Alibaba nacos configuration centers

spring cloud gateway service

Spring Cloud zuul a gateway service

Spring Cloud Gateway Services zuul two

Spring Cloud Gateway Services zuul three dynamic routing

Spring Cloud alibaba gateway sentinel zuul four current-limiting fuse

Spring Cloud gateway gateway services a

Spring Cloud gateway gateway service two assertions, filter

Spring Cloud gateway three custom filter GatewayFilter

How like you can share this concern public number.
file

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement. Reprinted please include public two-dimensional code number

Guess you like

Origin www.cnblogs.com/cloudxlr/p/11824831.html