Spring Cloud Gateway 动态路由

1.定义路由模型

import lombok.Data;

import java.util.LinkedHashMap;
import java.util.List;

/**
 * 路由模型
 *
 * @author 向振华
 * @date 2021/02/04 10:26
 */
@Data
public class RouteDefinitionDTO {

    /**
     * 路由的Id
     */
    private String id;

    /**
     * 路由断言集合配置
     */
    private List<PredicateDefinitionDTO> predicates;

    /**
     * 路由过滤器集合配置
     */
    private List<FilterDefinitionDTO> filters;

    /**
     * 路由规则转发的目标uri
     */
    private String uri;

    /**
     * 路由执行的顺序
     */
    private Integer order;

    @Data
    public static class PredicateDefinitionDTO {

        /**
         * 断言名称
         */
        private String name;

        /**
         * 断言规则
         */
        private LinkedHashMap<String, String> args;
    }

    @Data
    public static class FilterDefinitionDTO {

        /**
         * 过滤器名称
         */
        private String name;

        /**
         * 路由规则
         */
        private LinkedHashMap<String, String> args;
    }
}

2.定义路由修改controller

import com.bzcst.bop.gateway.entity.RouteDefinitionDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

import java.util.List;

/**
 * @author 向振华
 * @date 2021/02/04 10:26
 */
@RestController
@RequestMapping("/route")
public class DynamicRouteController {

    @Autowired
    private DynamicRouteService dynamicRouteService;

    /**
     * 获取路由
     */
    @GetMapping
    public Flux<RouteDefinition> get() {
        return dynamicRouteService.get();
    }

    /**
     * 更新路由
     */
    @PutMapping
    public void update(@RequestBody List<RouteDefinitionDTO> dto) {
        dynamicRouteService.updateRoutes(dto);
    }

    /**
     * 删除路由
     */
    @DeleteMapping("/{id}")
    public void delete(@PathVariable String id) {
        dynamicRouteService.delete(id);
    }
}

3.定义service处理动态路由,保存在本地内存

import com.bzcst.bop.gateway.entity.RouteDefinitionDTO;
import org.apache.commons.lang3.StringUtils;
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.RouteDefinitionLocator;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

/**
 * 动态路由服务
 *
 * @author 向振华
 * @date 2021/02/04 10:26
 */
@Service
public class DynamicRouteService implements ApplicationEventPublisherAware {

    @Resource
    private RouteDefinitionLocator routeDefinitionLocator;

    @Resource
    private RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher publisher;

    /**
     * 获取路由
     *
     * @return
     */
    public Flux<RouteDefinition> get() {
        return routeDefinitionLocator.getRouteDefinitions();
    }

    /**
     * 更新路由
     *
     * @param dtos
     */
    public void updateRoutes(List<RouteDefinitionDTO> dtos) {
        if (CollectionUtils.isEmpty(dtos)) {
            return;
        }
        for (RouteDefinitionDTO dto : dtos) {
            RouteDefinition routeDefinition = convertRouteDefinition(dto);
            update(routeDefinition);
        }
    }

    /**
     * 更新路由
     *
     * @param definition
     */
    public void update(RouteDefinition definition) {
        delete(definition.getId());
        save(definition);
    }

    /**
     * 删除路由
     *
     * @param id
     */
    public void delete(String id) {
        try {
            routeDefinitionWriter.delete(Mono.just(id)).subscribe();
        } catch (Exception ignored) {
        }
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }

    /**
     * 保存路由
     *
     * @param definition
     */
    public void save(RouteDefinition definition) {
        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }

    /**
     * 参数转换成路由对象
     *
     * @param dto
     * @return
     */
    private RouteDefinition convertRouteDefinition(RouteDefinitionDTO dto) {
        RouteDefinition definition = new RouteDefinition();
        // 设置id
        definition.setId(dto.getId());
        // 设置order
        definition.setOrder(dto.getOrder());
        // 设置断言
        List<PredicateDefinition> pdList = new ArrayList<>();
        List<RouteDefinitionDTO.PredicateDefinitionDTO> predicateDefinitionDTOList = dto.getPredicates();
        for (RouteDefinitionDTO.PredicateDefinitionDTO gpDefinition : predicateDefinitionDTOList) {
            PredicateDefinition predicate = new PredicateDefinition();
            predicate.setArgs(gpDefinition.getArgs());
            predicate.setName(gpDefinition.getName());
            pdList.add(predicate);
        }
        definition.setPredicates(pdList);
        // 设置过滤器
        List<FilterDefinition> filters = new ArrayList<>();
        List<RouteDefinitionDTO.FilterDefinitionDTO> gatewayFilters = dto.getFilters();
        for (RouteDefinitionDTO.FilterDefinitionDTO filterDefinition : gatewayFilters) {
            FilterDefinition filter = new FilterDefinition();
            filter.setName(filterDefinition.getName());
            filter.setArgs(filterDefinition.getArgs());
            filters.add(filter);
        }
        definition.setFilters(filters);
        // 设置uri
        URI uri = null;
        String uriStr = dto.getUri();
        if (StringUtils.isNotBlank(uriStr)) {
            String http = "http";
            if (uriStr.startsWith(http)) {
                uri = UriComponentsBuilder.fromHttpUrl(dto.getUri()).build().toUri();
            } else {
                uri = URI.create(dto.getUri());
            }
        }
        definition.setUri(uri);
        return definition;
    }

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

4.使用

这里会有个问题,修改本地配置文件已有的路由会重新添加一个新的路由。我的解决办法是,删除本地路由配置,全部采用动态路由配置。

路由接口一定要做好安全控制,可以加密加签,或者采用其他服务修改,然后使用redis定时更新、动态更新等

 

附入参json

[
 {
    "id":"xxx服务",
    "predicates":[
      {
        "name":"Path",
        "args":{
          "_genkey_0":"/xxx/**"
        }
      }
    ],
    "filters":[
      {
        "name":"Login",
        "args":{

        }
      },
      {
        "name":"FileSize",
        "args":{
          "_genkey_0":"10485760",
          "_genkey_1":"/*/x/z;/*/h/a"
        }
      }
    ],
    "uri":"lb://xxx",
    "order":0
  }
]

猜你喜欢

转载自blog.csdn.net/Anenan/article/details/113627950