您的位置 首页 java

SpringCloud系列——Zuul 动态路由

  前言

  Zuul 是在Spring Cloud Netflix平台上提供动态路由,监控,弹性,安全等边缘服务的框架, 是Netflix基于 jvm 的路由器和服务器端负载均衡器, 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门。本文基于上篇(SpringCloud系列——Ribbon 负载均衡)实现Zuul动态路由

   GitHub 地址:

  官方文档: Spring .io/spring-cloud-static/spring-cloud-netflix/2.1.0.RC2/single/spring-cloud-netflix.html#_router_and_filter_zuul

  代码编写

  首先我们在springCloud下面新建一个springboot项目:zuul-server,pom继承parent,并且在 Eureka 上面注册(还不会服务注册与发现的,请戳:SpringCloud系列——Eureka 服务注册与发现)

   maven 引入Zuul

         <!-- Zuul -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>  

  配置文件

 server.port=10010
spring.application.name=zuul-server
eureka.client.serviceUrl.defaultZone=
#健康检查(需要spring-boot-starter-actuator依赖)
eureka.client.healthcheck.enabled=true
# 续约更新时间间隔(默认30秒)
eureka.instance.lease-renewal-interval-in-seconds=10
# 续约到期时间(默认90秒)
eureka.instance.lease-expiration-duration-in-seconds=10

#zuul代理配置  zuul.routes.服务名.path,服务名要与注册的一致
#应用名映射
zuul.routes.myspringboot.path=/myspringboot/**
zuul.routes.myspringboot.service-id=myspringboot

#URL映射
#zuul.routes.myspringboot.path=/myspringboot/**
#zuul.routes.myspringboot-url.url=  

  自定义Zuul过滤器

  更多的检查规则后续慢慢健全

 /**
 * Zuul过滤器,实现了路由检查
 */
public class AccessFilter extends ZuulFilter {

    /**
     * 通过int值来定义过滤器的执行顺序
     */
    @Override
    public int filterOrder() {
        // PreDecoration之前运行
        return PRE_DECORATION_FILTER_ORDER - 1;
    }

    /**
     * 过滤器的类型,在zuul中定义了四种不同 生命周期 的过滤器类型:
     *     public  static  final String ERROR_TYPE = "error";
     *     public static final String POST_TYPE = "post";
     *     public static final String PRE_TYPE = "pre";
     *     public static final String ROUTE_TYPE = "route";
     */
    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    /**
     * 过滤器的具体逻辑
     */
    @Override
    public Object run() {
        RequestContext ctx =  Request Context.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        System.out.println(String.format("%s AccessFilter request to %s", request.getMethod(),request.getRequestURL().toString()));
        String accessToken = request.getParameter("accessToken");
        //有权限令牌
        if (!StringUtils.isEmpty(accessToken)) {
            ctx.setSendZuulResponse(true);
            ctx.setResponseStatusCode(200);
            //可以设置一些值
            ctx.set("isSuccess", true);
            return null;
        } else {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            ctx.setResponseBody("{"result":"accessToken is not correct!"}");
            //可以设置一些值
            ctx.set("isSuccess", false);
            return null;
        }
    }

    /**
     * 返回一个 boolean 类型来判断该过滤器是否要执行
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }
}  

  启动类

  添加@EnableZuulProxy注解并使用自定义过滤器

 @EnableZuulProxy
@SpringBootApplication
public class ZuulServerApplication {

    public static  void  main(String[] args) {
        SpringApplication.run(ZuulServerApplication.class, args);
    }

    @Bean
    public AccessFilter accessFilter() {
        return new AccessFilter();
    }
}  

  效果演示

  启动所有项目,我们在Eureka上注册了四个服务,相比上篇(SpringCloud系列——Ribbon 负载均衡)多了一个Zuul

  浏览器访问 、

   这个端口对外暴露,相对于总入口,后面接不同的路径由,Zuul路由到对应的服务上

  1、没有accessToken是,无法通过检查

  2、携带accessToken时,可正常路由,并且Feign调用、Ribbon负载均衡

  后记

  我们为什么要使用Zuul呢?

  1、请求校验、路由转发,接口校验与业务逻辑分离

  2、隐藏诸多服务路径,只暴露统一入口,安全

  更多Zuul配置,请看官方文档

  更新

   2021-12-24更新 :动态更新zuul路由配置

  正常zuul路由配置是在配置文件里设置,当我们想动态调整,又不想重启zuul-server服务时:

    1、zuul-server会实时从eureka-server注册表中拉取在线服务更新路由

    2、可以从config-server配置中心获取最新配置

    3、可以从数据库读取表数据获取最新配置

  这里记录一下第三种方案

  mysql新建zuul路由表

 -- ----------------------------
-- Table structure for zuul_route
-- ----------------------------
DROP TABLE IF EXISTS `zuul_route`;
CREATE TABLE `zuul_route`  (
  `id` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '表id(一般直接用service_id的值即可)',
  `service_id` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '服务名',
  `path` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '路径',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'zuul路由表' ROW_FORMAT = Compact;

-- ----------------------------
-- Records of zuul_route
-- ----------------------------
INSERT INTO `zuul_route` VALUES ('service-a', 'service-a', '/service-a/**');
INSERT INTO `zuul_route` VALUES ('service-b', 'service-b', '/service-b/**');
INSERT INTO `zuul_route` VALUES ('service-c', 'service-c', '/service-c/**');
INSERT INTO `zuul_route` VALUES ('sso-server', 'sso-server', '/sso-server/**');  

  pom文件引入

         <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--  Jdbc Template -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>  

  配置文件注释路由配置,新增数据库连接配置

 # 省略其他代码...

#zuul路由配置
# 应用名映射     zuul.routes.服务名.[path、service-id],服务名要与eureka注册的一致
#zuul.routes.service-a.path=/service-a/**
#zuul.routes.service-a.service-id=service-a
#zuul.routes.service-b.path=/service-b/**
#zuul.routes.service-b.service-id=service-b
#zuul.routes.sso-server.path=/sso-server/**
#zuul.routes.sso-server.service-id=sso-server

#URL映射
#zuul.routes.service-a.path=/service-a/**
#zuul.routes.service-a-url.url=

#数据库连接配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456  

  新建一个ZuulRouteLocator,实现InitializingBean接口,主要用于afterPropertiesSet 回调 进行zuul路由初始化

 package cn.huanzi.qch.zuul.zuulserver.config;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory. annotation .Autowired;
import org.springframework.cloud.netflix.zuul.filters.*;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.ZuulRoute;
import org.springframework.stereotype.Component;

import  java .util.List;
import java.util.Map;

/**
 * 自定义zuul路由
 */
@Component
public class ZuulRouteLocator implements InitializingBean {

    @Autowired
     private  CompositeRouteLocator compositeRouteLocator;

    @Autowired
    private ZuulProperties zuulProperties;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 刷新zuul路由
     *
     * 数据来源:
     *      配置文件
     *      数据库zuul路由表
     */
    public List<Route> refreshRoutes() {
        //读取原配置文件的路由配置
         Map <String, ZuulRoute> routes = zuulProperties.getRoutes();

        //读取数据库zuul路由表配置
       List<ZuulRoute> routeList = jdbcTemplate.query("select id,service_id,path from zuul_route", new BeanPropertyRowMapper<>(ZuulRoute.class));

        //routeList数据并添加到routes中
        for (ZuulRoute route : routeList) {
            routes.put(route.getId(), route);
        }

        //刷新zuul路由
        zuulProperties.setRoutes(routes);
        compositeRouteLocator.refresh();

        //返回现有路由
        return compositeRouteLocator.getRoutes();
    }

    /**
     * 初始化路由信息
     */
    @Override
    public void afterPropertiesSet() {
        this.refreshRoutes();
    }
}  

  在写一个controller,用于主动刷新

 package cn.huanzi.qch.zuul.zuulserver.controller;

import cn.huanzi.qch.zuul.zuulserver.config.ZuulRouteLocator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.Route;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class ZuulRouteController {

    @Autowired
    ZuulRouteLocator zuulRouteLocator;

    /**
     * 读取数据库zuul表,刷新zuul路由
     */
    @GetMapping("/zuulRouteRefresh")
    public List<Route> zuulRouteRefresh(){
        return zuulRouteLocator.refreshRoutes();
    }

}  

  

  代码开源

  代码已经开源、托管到我的GitHub、码云:

  GitHub:

  码云:

版权声明

作者:huanzi-qch

出处:

若标题中有“转载”字样,则本文版权归原作者所有。若无转载字样,本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.

文章来源:智云一二三科技

文章标题:SpringCloud系列——Zuul 动态路由

文章地址:https://www.zhihuclub.com/198652.shtml

关于作者: 智云科技

热门文章

评论已关闭

5条评论

  1. My Week With Marilyn is based on the Colin Clark memoir about his fleeting encounter with the famous actress in the summer of 1956 when he was a film set assistant on The Prince and the Showgirl

  2. Gene mutations that confer MH susceptibility have been identified in three genes, although there are undoubtedly two or more other genes that can confer susceptibility

  3. Hila Wiener 1, Bat Hen Annie Daviko Levi 1, 2, Ilona Brants 1, Svetlana Buslovich Khayumov 1, Olga Mandelgeim 1, Gila Meirson 1, Gideon Karplus 1, Ilan Dalal 1

  4. Alterations of gyrA, gyrB, and parC and activity of efflux pump in fluoroquinolone resistant Acinetobacter baumannii Urinalysis, stool guaiac tests, and chest radiography for vasculitis

网站地图