Gateway在数据库中实现动态网关

实现思路:

1.在网关启动默认加载时,从数据库中查询网关配置

2.将数据库的内容读取保存在网关内存中

 

为什么不建议使用配置中心呢?

需要定义json格式配置,阅读性差,采用表结构设计可阅读性很强.

 

网关配置更新思路:

1.更新网关配置到数据库

2.调用网关api更新网关到内存中

 

动态路由表结构

CREATE TABLE `gateway` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `route_id` varchar(11) DEFAULT NULL,

  `route_name` varchar(255) DEFAULT NULL,

  `route_pattern` varchar(255) DEFAULT NULL,

  `route_type` varchar(255) DEFAULT NULL,

  `route_url` varchar(255) DEFAULT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;

pom.xml



		
			org.springframework.cloud
			spring-cloud-starter-gateway
			2.2.0.RELEASE
		
		
			org.apache.commons
			commons-lang3
		
		
			org.springframework.cloud
			spring-cloud-gateway-core
			2.2.0.RELEASE
		
		
			com.alibaba.cloud
			spring-cloud-starter-alibaba-nacos-discovery
			2.2.0.RELEASE
		
		
			org.mybatis.spring.boot
			mybatis-spring-boot-starter
			1.1.1
		
		
		
			mysql
			mysql-connector-java
		
		
		
			com.alibaba
			druid
			1.0.14
		

	

application.yml

server:
  port: 8011
####服务网关名称
spring:
  application:
    name: infosys-gateway2
  cloud:
     gateway:
      discovery:
        locator:
          enabled: true
     nacos:
       discovery:
        server-addr: 192.168.234.135:8848
        
  datasource:
    url: jdbc:mysql://192.168.234.135:3306/mysql?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
    username: root
    password: jiayoubing
    driver-class-name: com.mysql.jdbc.Driver

GatewayService.java

package com.infosys.china.service;

import java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;

import com.infosys.china.entity.GateWayEntity;
import com.infosys.china.mapping.GatewayMapper;

import reactor.core.publisher.Mono;

/**
 * 
 * 系统在加载时,读取数据库中的路由配置信息
 * 
 * @author Jiayoubing
 * @version [版本号,2020年4月17日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Service
public class GatewayService implements ApplicationEventPublisherAware, GatewayRoutesService
{
    private ApplicationEventPublisher publisher;

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    @Autowired
    private GatewayMapper gatewayMapper;

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

    public String loadRoute(GateWayEntity gateWayEntity)
    {
        RouteDefinition definition = new RouteDefinition();
        Map predicateParams = new HashMap<>(8);
        PredicateDefinition predicate = new PredicateDefinition();
        FilterDefinition filterDefinition = new FilterDefinition();
        Map filterParams = new HashMap<>(8);
        URI uri = null;
        if ("0".equals(gateWayEntity.getRouteType()))
        {
            // 如果配置路由type为0的话 则从数据库中获取服务地址
            uri = UriComponentsBuilder.fromUriString(gateWayEntity.getRouteUrl()).build().toUri();
        }
        else
        {
            uri = UriComponentsBuilder.fromHttpUrl(gateWayEntity.getRouteUrl()).build().toUri();
        }

        // 定义的路由唯一的id
        definition.setId(gateWayEntity.getRouteId());
        predicate.setName("Path");
        // 路由转发地址
        predicateParams.put("pattern", gateWayEntity.getRoutePattern());
        predicate.setArgs(predicateParams);

        // 名称是固定的, 路径去前缀
        filterDefinition.setName("StripPrefix");
        filterParams.put("_genkey_0", "1");
        filterDefinition.setArgs(filterParams);
        definition.setPredicates(Arrays.asList(predicate));
        definition.setFilters(Arrays.asList(filterDefinition));
        definition.setUri(uri);
        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        this.publisher.publishEvent(new RefreshRoutesEvent(this));

        return "success";
    }

    /**
     * 获取所有网关路由数据 TODO 简单描述该方法的实现功能(可选).
     * 
     * @see com.infosys.china.service.GatewayRoutesService#findAll()
     * @return
     * @throws Exception
     */
    @Override
    public List findAll() throws Exception
    {
        List gateWayEntities = gatewayMapper.gateWayAll();
        return gateWayEntities;
    }

    @Override
    public GateWayEntity save(GateWayEntity gatewayDefine) throws Exception
    {
        GateWayEntity gateWayEntity = gatewayMapper.saveGateWay(gatewayDefine);
        return gateWayEntity;
    }

    @Override
    public void deleteById(String id) throws Exception
    {
        gatewayMapper.delGateWay(id);

    }

    @Override
    public boolean existsById(String id) throws Exception
    {
        return gatewayMapper.existsById(id);
    }


    public String loadRouteDefinition() throws Exception
    {
        List gateWayEntities = findAll();
        for (GateWayEntity gb : gateWayEntities)
        {
            loadRoute(gb);
        }
        return "网关路由数据初始化成功!";
    }

}

GatewayRoutesService.java

package com.infosys.china.service;

import java.util.List;

import com.infosys.china.entity.GateWayEntity;

public interface GatewayRoutesService
{
    List findAll() throws Exception;

    GateWayEntity save(GateWayEntity gatewayDefine) throws Exception;

    void deleteById(String id) throws Exception;

    boolean existsById(String id) throws Exception;

}

 

 

你可能感兴趣的:(Gateway在数据库中实现动态网关)