百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

SpringCloud系列——Zuul 动态路由

lipiwang 2024-11-17 13:25 9 浏览 0 评论

  前言

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

  GitHub地址:https://github.com/Netflix/zuul

  官方文档:https://cloud.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=http://localhost:1111/eureka/
#健康检查(需要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=http://localhost:10087/

  自定义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 = RequestContext.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

  浏览器访问 http://localhost:10010/myspringboot/feign/ribbon、http://localhost:10010/myspringboot/feign/ribbon?accessToken=123456

  http://localhost:10010/ 这个端口对外暴露,相对于总入口,后面接不同的路径由,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>

        <!-- JdbcTemplate -->
        <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=http://localhost:10081/

#数据库连接配置
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();
    }

}

  http://localhost:10010/zuulRouteRefresh

  代码开源

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

  GitHub:https://github.com/huanzi-qch/springCloud

  码云:https://gitee.com/huanzi-qch/springCloud

版权声明

作者:huanzi-qch

出处:https://www.cnblogs.com/huanzi-qch

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

相关推荐

微软Office Open XML中的数字签名漏洞

MicrosoftOffice是最广泛使用的办公文档应用程序之一。对于重要文件,如合同和发票,可以对其内容进行签名,以确保其真实性和完整性。自2019年以来,安全研究人员发现了针对PDF和ODF等其...

Javaweb知识 day12 XML(javaweb中xml作用)

一、XML:1.1概念:ExtensibleMarkupLanguage可扩展标记语言*可扩展:标签都是自定义的。<user><student>1.2功能:...

易筋洗髓功——内外同修方可致远(易筋洗髓功口诀)

达摩祖师所传易筋、洗髓两经,一分为二,二实为一,无非以方便法门接引众生,而归于慈悲清净之心地。修炼《易筋经》是为强身健体,修炼《洗髓经》是为修心养性,此二者相辅相成,内外兼修,缺一不可。这是一套传统中...

《增演易筋洗髓内功图说》17卷(1930年(清)周述官撰 4

《增演易筋洗髓内功图说》17卷(1930年(清)周述官撰 5

道家洗髓功修炼要义,洗髓功如何做到丹田聚气?

不管是道家洗髓功,还是洗髓经,其修炼的关键点就在于得气、行气、聚气...那么,作为洗髓功修炼者,具体该怎么做呢?在实际修炼中,就洗髓功的修炼方法来讲,我们可以简单的归纳为修炼三部曲,其具体表现如下:一...

「清风聊练功」师门传我易筋经:聊聊我的学习经历和正身图感受

一个人的眼界认识,是随着是自身的知识积累和水平不断成长的。开篇为什么要说这么一句呢?是从我的学习经历上感受明显的这句话:一处不到一处迷。我们学传统武术,内功功法,也是从小白到明白一步步走的,走的越远,...

内功外练功介绍(练内功 外功)

这里介绍我练习的两套动功心得体会。是老道长的八部金刚功、长寿功和增演易筋洗髓经。八部金刚功外练奇经八脉,练出健康强壮的好身体还是可以的,长寿功也是内练功法。这部功法很好的预防效果。这个大家都认同的。说...

孔德易筋洗髓大全注解(下)(孔德易筋经教学视频)

...

《增演易筋洗髓内功图说》17卷(1930年(清)周述官撰 1

少林空悟老师珍藏

国术典籍:《增演易筋洗髓内功图说》【2024年8月编校】

《增演易筋洗髓内功图说》系养生气功著作,全书共十八卷。清周述官编撰于光绪二十一年(1895年)。清光绪十九年(1893年),僧人静一空悟将少林功法传授于周述官,并将《增益易筋洗髓内功图说》十二卷(按,...

小说:自媒体小白的修道之路-洗髓(自媒体小白运营技巧)

谁应了谁的劫,谁又变成了谁的执念。当沧海遗忘了桑田,这世间又多了一个不回家的人!异域空间中,知生缓缓起身,目光扫了一下小帝后,又转身看向画板上的那朵白色蒲公英,自言道:“白瑛,这一世我们莫要再辜负了!...

这才是少林洗髓经真相:它是静功和导引术与八段锦暗合

不少朋友误解易筋经和洗髓经,将其简单归为强力呼吸的吐纳功以及为了提升房中的关窍功。事实上易筋经和洗髓经是两部功法:易筋经主要为炼体,包含以膜论为核心的十二月怕打筋膜法,以及辅助的呼吸、导引功法;洗髓经...

孔德易筋洗髓大全注解(上)(孔德易筋经洗髓经视频)

...

洗髓经传承与心得(二)(《洗髓经》)

...

取消回复欢迎 发表评论: