资讯 小学 初中 高中 语言 会计职称 学历提升 法考 计算机考试 医护考试 建工考试 教育百科
栏目分类:
子分类:
返回
空麓网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
空麓网 > 计算机考试 > 软件开发 > 后端开发 > Java

SpringCloudGateway路由定义存至Mysql数据库

Java 更新时间: 发布时间: 计算机考试归档 最新发布

SpringCloudGateway路由定义存至Mysql数据库

SpringCloudGateway路由定义存至Mysql数据库

SpringCloudGateway默认根据配置文件或代码在启动时路由定义存在内存中,如果要修改路由配置,需要改动配置文件或代码后重启网关,十分不灵活。

官方提供了RedisRouteDefinitionRepository可以将配置存放之Redis中,使用spring.cloud.gateway.redis-route-definition-repository.enabled开启。

可以实现RouteDefinitionRepository接口,将路由配置保存至Mysql中。

使用的SpringCloud版本为2021.0.5,文章编写于2022-12-12日。

ORM使用SpringDataR2DBC,相关教程请自行查找。

项目POM引入


    org.springframework.boot
    spring-boot-starter-data-r2dbc


    com.github.jasync-sql
    jasync-r2dbc-mysql

路由定义实体

@Table(name = "`gateway_route_define`")
public class GatewayRouteDefineEntity implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    private String id;

    private String uri;

    private String predicates;

    private String filters;

    private String metadata;

    @Column("`is_enable`")
    private Boolean enable;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUri() {
        return uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }

    public String getPredicates() {
        return predicates;
    }

    public void setPredicates(String predicates) {
        this.predicates = predicates;
    }

    public String getFilters() {
        return filters;
    }

    public void setFilters(String filters) {
        this.filters = filters;
    }

    public String getMetadata() {
        return metadata;
    }

    public void setMetadata(String metadata) {
        this.metadata = metadata;
    }

    public Boolean isEnable() {
        return enable;
    }

    public void setEnable(Boolean enable) {
        this.enable = enable;
    }
}

DAO层

@Repository
public interface GatewayRouteDefineDao extends ReactiveCrudRepository {

    
    Flux findAllByEnableTrue();
}

Service层

public interface GatewayRouteDefineService {

    
    Flux findAll();

    
    Mono save(@RequestBody @Validated GatewayRouteDefineEntity entity);

    
    Mono deleteById(@PathVariable("id") String id);

    
    Mono refreshRouteDefinition();
}
@Service
public class GatewayRouteDefineServiceImpl implements GatewayRouteDefineService {

    private static final Logger log = LoggerFactory.getLogger(GatewayRouteDefineServiceImpl.class);

    private final GatewayRouteDefineDao gatewayRouteDefineDao;

    private final ApplicationEventPublisher publisher;


    public GatewayRouteDefineServiceImpl(GatewayRouteDefineDao gatewayRouteDefineDao,
                                         ApplicationEventPublisher publisher) {
        this.gatewayRouteDefineDao = gatewayRouteDefineDao;
        this.publisher = publisher;
    }

    @Override
    public Flux findAll() {
        return gatewayRouteDefineDao.findAllByEnableTrue();
    }

    @Override
    public Mono save(GatewayRouteDefineEntity entity) {
        return gatewayRouteDefineDao.save(entity);
    }

    @Override
    public Mono deleteById(String id) {
        return gatewayRouteDefineDao.deleteById(id);
    }

    @Override
    public Mono refreshRouteDefinition() {
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return Mono.empty();
    }
}

实现RouteDefinitionRepository

@Configuration
public class RouteDefinitionConfiguration {

    @Bean
    public DbRouteDefinitionRepository dbRouteDefinitionRepository(
            GatewayRouteDefineService gatewayRouteDefineService) {
        return new DbRouteDefinitionRepository(gatewayRouteDefineService);
    }

    public static class DbRouteDefinitionRepository implements RouteDefinitionRepository {

        private final GatewayRouteDefineService gatewayRouteDefineService;

        public DbRouteDefinitionRepository(GatewayRouteDefineService gatewayRouteDefineService) {
            this.gatewayRouteDefineService = gatewayRouteDefineService;
        }

        @Override
        public Flux getRouteDefinitions() {
            return gatewayRouteDefineService.findAll()
                    .map(entity -> {
                        try {
                            return GatewayRouteDefineUtils.convert(entity);
                        } catch (URISyntaxException | JsonProcessingException e) {
                            throw new RuntimeException(e);
                        }
                    });
        }

        @Override
        public Mono save(Mono route) {
            return route.flatMap(r -> {
                try {
                    GatewayRouteDefineEntity entity = GatewayRouteDefineUtils.convert(r);
                    return gatewayRouteDefineService.save(entity).then();
                } catch (JsonProcessingException e) {
                    return Mono.error(new RuntimeException(e));
                }
            });
        }

        @Override
        public Mono delete(Mono routeId) {
            return routeId.flatMap(gatewayRouteDefineService::deleteById);
        }
    }
}

工具类

public class GatewayRouteDefineUtils {

    private static final ObjectMapper OBJECT_MAPPER;

    static {
        OBJECT_MAPPER = new ObjectMapper();
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    public static RouteDefinition convert(GatewayRouteDefineEntity entity) throws URISyntaxException, JsonProcessingException {
        RouteDefinition definition = new RouteDefinition();
        definition.setId(entity.getId());
        definition.setUri(new URI(entity.getUri()));

        if (entity.getPredicates() != null) {
            List predicateDefinitions = OBJECT_MAPPER.readValue(
                    entity.getPredicates(),
                    new TypeReference>() { });
            definition.setPredicates(predicateDefinitions);
        }

        if (entity.getFilters() != null) {
            List filterDefinitions = OBJECT_MAPPER.readValue(
                    entity.getFilters(),
                    new TypeReference>() { });
            definition.setFilters(filterDefinitions);
        }
        return definition;
    }

    public static GatewayRouteDefineEntity convert(RouteDefinition definition) throws JsonProcessingException {
        GatewayRouteDefineEntity entity = new GatewayRouteDefineEntity();
        entity.setId(definition.getId());
        entity.setUri(definition.getUri().toString());
        entity.setPredicates(OBJECT_MAPPER.writeValueAsString(definition.getPredicates()));
        entity.setFilters(OBJECT_MAPPER.writeValueAsString(definition.getFilters()));
        return entity;
    }
}

测试Controller

@RestController
public class TestController {

    private static final Logger log = LoggerFactory.getLogger(TestController.class);

    private final GatewayRouteDefineService gatewayRouteDefineService;

    public TestController(GatewayRouteDefineService gatewayRouteDefineService) {
        this.gatewayRouteDefineService = gatewayRouteDefineService;
    }

    @RequestMapping("/refresh_route")
    public Mono refreshRoute() {
        return gatewayRouteDefineService.refreshRouteDefinition()
                .thenReturn("refresh success");
    }
}

数据库表

CREATE TABLE `gateway_route_define`  (
  `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键',
  `uri` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '目的地址',
  `predicates` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '断言定义',
  `filters` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '过滤器定义',
  `metadata` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '扩展数据',
  `is_enable` tinyint(4) NULL DEFAULT NULL COMMENT '是否启用  0:否  1:是',
  `create_time` datetime(3) NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '网关路由定义表' ROW_FORMAT = Dynamic;

插入一条测试数据

INSERT INTO `gateway_route_define` VALUES ('c707a482-77a3-11ed-a1eb-0242ac120002', 'https://www.baidu.com', '[{"name":"Path","args":{"pattern":"/baidu"}}]', '[{"name":"RewritePath","args":{"regexp":"/baidu/?(?.*)","replacement":"/$\\{segment}"}},{"name":"GuavaRateLimiter","args":{"limit":"5"}}]', '{}', 1, '2022-12-12 11:46:55.000');

其实数据库保存的字段就是RouteDefinition类中的字段,其中predicates、filters、metadata字段为JSON格式的数据。

路由定义序列化

Predicate序列化

其实就是对PredicateDefinition类进行序列化,包含name和args两个字段,其中args需要去org.springframework.cloud.gateway.handler.predicate路径下找具体的工厂类,里面有各参数的名称
例如

spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment},/blue/{segment}

这条路由规则中的

Path=/red/{segment},/blue/{segment}

其实现类是PathRoutePredicateFactory,那么args参数就是由PathRoutePredicateFactory.Config序列化而来。其余predicate和filter都是按此规则,这样应该就能理解插入的测试数据中predicates和filters字段的含义了。

测试

启动网关,会自动去数据库加载路由定义,当数据库路由修改后,可以调用GatewayRouteDefineService#refreshRouteDefinition来刷新路由,其实原理就是触发一个RefreshRoutesEvent事件,SpringCloudGateway会重新加载路由。

转载请注明:文章转载自 http://www.konglu.com/
本文地址:http://www.konglu.com/it/1093617.html
免责声明:

我们致力于保护作者版权,注重分享,被刊用文章【SpringCloudGateway路由定义存至Mysql数据库】因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理,本文部分文字与图片资源来自于网络,转载此文是出于传递更多信息之目的,若有来源标注错误或侵犯了您的合法权益,请立即通知我们,情况属实,我们会第一时间予以删除,并同时向您表示歉意,谢谢!

我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2023 成都空麓科技有限公司

ICP备案号:蜀ICP备2023000828号-2