Spring boot 2.0 zuul routes db网关

前言:该文章只是记录自己平时的点点滴滴.来激励自己成长.长成自己喜欢的人!

环境:

  1. 电脑 Mac 10.13.1
  2. IntelliJ IDEA 2018.2 (Ultimate Edition)
  3. Spring boot  2.0.1.RELEASE

实现方案:

  1. 对外提供接口只暴漏一个接口名称,通过入参的形式路由服务对象
  2. 要求数据加密
  3. 要求传输每一步有日志输出

实现细节:

  1. Zuul 
  2. Feign
  3. ZuulFilter
  4. ErrorController
  5. RefreshableRouteLocator

这里记录 RefreshableRouteLocator 实现db路由配置.

  • DB - table
CREATE TABLE `saas_zuul_route` (
  `id` varchar(64) NOT NULL COMMENT 'zuul routes id',
  `path` varchar(64) DEFAULT NULL COMMENT 'zuul path',
  `service_id` varchar(64) DEFAULT NULL COMMENT 'zuul serviceId',
  `url` varchar(64) DEFAULT NULL COMMENT 'zuul url',
  `enabled` tinyint(1) DEFAULT '1' COMMENT '是否启用,默认启用',
  `retryable` tinyint(1) DEFAULT '1' COMMENT '是否重复使用',
  `strip_prefix` tinyint(1) DEFAULT '1' COMMENT '是否添加前缀',
  `prefix` varchar(32) DEFAULT NULL,
  `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_update` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
  `state` tinyint(1) DEFAULT '1' COMMENT '数据状态',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='zuul 动态路由主表'

CREATE TABLE `saas_zuul_route_detail` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `zuul_route_id` varchar(64) DEFAULT NULL COMMENT 'zuul routes id',
  `service_path` varchar(64) DEFAULT NULL COMMENT '微服务controller path',
  `service_name` varchar(64) DEFAULT NULL COMMENT '对外service',
  `zuul_name` varchar(64) DEFAULT NULL COMMENT '微服务中文名称',
  `gmt_create` datetime DEFAULT NULL COMMENT '创建时间',
  `gmt_update` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
  `state` tinyint(1) DEFAULT '1' COMMENT '数据状态',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='zuul 动态路由详情表'

业务逻辑代码(借鉴 https://blog.csdn.net/tianyaleixiaowu/article/details/77933295 )

public class DBRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {

    private JdbcTemplate jdbcTemplate;

    private ZuulProperties properties;

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public DBRouteLocator(String servletPath, ZuulProperties properties) {
        super(servletPath, properties);
        this.properties = properties;
        log.info("servletPath:{}", servletPath);
    }

    //父类已经提供了这个方法,这里写出来只是为了说明这一个方法很重要!!!
//    @Override
//    protected void doRefresh() {
//        super.doRefresh();
//    }


    @Override
    public void refresh() {
        doRefresh();
    }

    @Override
    protected Map<String, ZuulProperties.ZuulRoute> locateRoutes() {
        LinkedHashMap<String, ZuulProperties.ZuulRoute> routesMap = new LinkedHashMap<>();
        routesMap.putAll(super.locateRoutes());
        //从db中加载路由信息
        routesMap.putAll(locateRoutesFromDB());
        LinkedHashMap<String, ZuulProperties.ZuulRoute> values = new LinkedHashMap<>();
        for (Map.Entry<String, ZuulProperties.ZuulRoute> entry : routesMap.entrySet()) {
            log.info("数据集合 + {}",entry);
            String path = entry.getKey();
            if (!path.startsWith("/")) {
                path = "/" + path;
            }
            if (StringUtil.hasText(this.properties.getPrefix())) {
                path = this.properties.getPrefix() + path;
                if (!path.startsWith("/")) {
                    path = "/" + path;
                }
            }
            values.put(path, entry.getValue());
        }
        return values;
    }

    private Map<String, ZuulProperties.ZuulRoute> locateRoutesFromDB() {
        Map<String, ZuulProperties.ZuulRoute> routes = new LinkedHashMap<>();
        List<ZuulRouteDO> results = jdbcTemplate.query("select * from saas_zuul_route where enabled = true ", new BeanPropertyRowMapper<>(ZuulRouteDO.class));
        for (ZuulRouteDO result : results) {
            if (StringUtil.isEmptys(result.getPath()) ) {
                continue;
            }
            if (StringUtil.isEmptys(result.getServiceId()) && StringUtil.isEmptys(result.getUrl())) {
                continue;
            }
            ZuulProperties.ZuulRoute zuulRoute = new ZuulProperties.ZuulRoute();
            try {
                BeanUtils.copyProperties(result, zuulRoute);
            } catch (Exception e) {
                log.error("=============load zuul route info from db with error==============", e);
            }
            routes.put(zuulRoute.getPath(), zuulRoute);
        }
        return routes;
    }

    @Data
    private static class ZuulRouteDO {
        private String id;
        private String path;
        private String serviceId;
        private String url;
        private Boolean stripPrefix = true;
        private Boolean retryable;
        private Boolean enabled;
        private String prefix;
        private Date gmtCreate;
        private Date gmtUpdate;
        private String state;
        private String remark;
    }

 

zuul 启动时加载配置

@Configuration
public class ZuulGatewayConfig {

    @Autowired
    JdbcTemplate jdbcTemplate;
    @Autowired
    ZuulProperties zuulProperties;
    @Autowired
    ServerProperties server;

    /**
     * @return DBRouteLocator 动态路由
     */
    @Bean
    public DBRouteLocator routeLocator() {
        DBRouteLocator routeLocator = new DBRouteLocator(server.getServlet().getServletPrefix(), this.zuulProperties);
        routeLocator.setJdbcTemplate(jdbcTemplate);
        return routeLocator;
    }

}

 

刷新缓存.我这里用的是db链接.所以不需要刷新缓存.毕竟spring boot 2.0 提供了定时刷新任务

bootstrap.yml

server:
  port: 8080

spring:
  application:
    name: zuul
  cloud:
    config:
      enabled: false #关闭加载远程配置

logging:
  level:
    root: INFO

application.yml 配置,因为db读取routes . 所以这里不配置任何routes

spring:
  datasource:
    name: mysql_dev
    type: com.alibaba.druid.pool.DruidDataSource
    #druid相关配置
    druid:
      #监控统计拦截的filters
      #配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙,防止sql注入
      filters: stat
      driver-class-name: com.mysql.jdbc.Driver
      #基本属性
      url: jdbc:mysql://localhost/abc
      username: root
      password: dasd
      #配置初始化大小/最小/最大
      initial-size: 1
      min-idle: 1
      max-active: 20
      #获取连接等待超时时间
      max-wait: 60000
      #间隔多久进行一次检测,检测需要关闭的空闲连接
      time-between-eviction-runs-millis: 60000
      #一个连接在池中最小生存的时间
      min-evictable-idle-time-millis: 300000
      validation-query: SELECT 'x'
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      #打开PSCache,并指定每个连接上PSCache的大小。oracle设为true,mysql设为false。分库分表较多推荐设置为false
      pool-prepared-statements: false
      max-pool-prepared-statement-per-connection-size: 20
      filter:
        stat:
          log-slow-sql: true

eureka:
  client:
    service-url:
      defaultZone: http://admin:admin@localhost:1111/eureka
  instance:
    prefer-ip-address: true #开启ip访问. (默认主机名访问)
    instance-id: ${spring.application.name}:${server.port} #主机名:主机ip:port

zuul:
  ignoredServices: '*' # 所有的微服务 ignored, 拒绝


 

 


 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值