一起来学Spring Cloud | 第六章:服务网关 ( Zuul)
本章节,我们讲解springcloud重要组件:微服务网关Zuul。如果有同学从第一章看到本章的,会发现我们已经讲解了大部分微服务常用的基本组件。
已经讲解过的:
一起来学Spring Cloud | 第一章 :如何搭建一个多模块的springcloud项目
一起来学Spring Cloud | 第二章:服务注册和发现组件 (Eureka)
一起来学Spring Cloud | 第三章:服务消费者 (负载均衡Ribbon)
一起来学Spring Cloud | 第四章:服务消费者 ( Feign )
一起来学Spring Cloud | 第五章:熔断器 ( Hystrix)
本章正在讲解的:一起来学Spring Cloud | 第六章:服务网关 ( Zuul)
下章即将讲解的: 一起来学Spring Cloud | 第七章:分布式配置中心(Spring Cloud Config)
刚入门的同学,如果把前面这七章都理解清楚,并且自己搭建一遍,在工作中,我们已经可以搭建一个最简单的微服务项目了,我曾经看过一个创业公司,他们使用微服务框架时,就用以上的组件在生产上运行着简单的后台业务系统。
一、Zuul简介:
Zuul是Netflix开源的微服务网关,它可以和Eureka、Feign、hystrix等组件配合使用,Zuul的核心是一系列过滤器,它主要功能是路由转发和过滤器。
在实际项目中,一个复杂的业务系统后台,少则几十个服务模块,多则成百上千,随着业务场景的不断变更,我们的系统也会不断在演变,就会遇到如下的几个问题:
1. 如果存在跨域请求,多个微服务在一定的场景下处理相对复杂。
2. 客户端多次请求不同的微服务,增加了客户端的复杂性。
3. 认证复杂,每个微服务都需要独立认证。
4. 难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个微服务合并成一个或者将一个微服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很能实施。
5. 某些微服务可能使用了防火墙/浏览器不友好的协议,直接访问会有一定困难。
Zuul提供的作用:
1. 提供统一服务入口,微服务对前台透明
2. 聚合后台服务,节省流量,提升性能
3. 安全,过滤,流控等API管理功能
4. 提供统一服务出口,解耦
二、Zuul实现路由功能:
1. 在前面2章讲解的两个服务模块上,新增两个方法,模拟前端请求,做为本次zuul的测试接口
springcloud-ribbon-client模块的RibbonController类,增加/testzuul接口,具体模块信息参考:一起来学Spring Cloud | 第三章:服务消费者 (负载均衡Ribbon)
package com.haly.controller; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import com.haly.service.RibbonService; @RestController
public class RibbonController {
@Autowired
RibbonService ribbonService; @GetMapping(value = "/getHello")
public String getHello(@RequestParam String name) {
return ribbonService.getHello(name);
} @GetMapping(value = "/testzuul")
public String testzuul(@RequestParam String name) {
return name +"这是springcloud-ribbon-clientd的服务接口";
} }
springcloud-feign-client模块的FeignController类,增加/testzuul接口,具体模块信息参考:一起来学Spring Cloud | 第四章:服务消费者 ( Feign )
package com.haly.controller; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import com.haly.romote.FeignRemoteService; @RestController
public class FeignController { @Autowired
FeignRemoteService feignRemoteService; @GetMapping(value = "/getHello")
public String getHello(@RequestParam String name) {
return feignRemoteService.hello(name);
} @GetMapping(value = "/testzuul")
public String testzuul(@RequestParam String name) {
return name +",这是springcloud-feign-client的服务接口";
}
}
2. 新建一个新的zuul服务工程,名称为:springcloud-zuul-server
①:修改pom.xml文件,parent标签引用的是父文件,具体父文件配置,参考:一起来学Spring Cloud | 第一章 :如何搭建一个多模块的springcloud项目
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.haly</groupId>
<artifactId>springcloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent> <groupId>com.haly</groupId>
<artifactId>springcloud-zuul-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-zuul-server</name>
<description>新建一个zuuld项目</description> <dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
②:新增模块启动类SpringcloudZuulServerApplication
注解@EnableZuulProxy,表示开启zuul的功能,它默认也具有@EnableCircuitBreaker和@EnableDiscoveryClient两个注解的功能
package com.haly; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy; @EnableZuulProxy
@SpringBootApplication
public class SpringcloudZuulServerApplication { public static void main(String[] args) {
SpringApplication.run(SpringcloudZuulServerApplication.class, args);
} }
③:application.properties加上以下的配置代码:
server.port=9700
spring.application.name=springcloud-zuul-server
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/ zuul.ignored-services: "*" zuul.routes.a.path = /api/a/**
zuul.routes.a.serviceId = springcloud-feign-client zuul.routes.b.path = /api/b/**
zuul.routes.b.serviceId = springcloud-feign-client
先解释下配置含义
zuul.ignored-services: "*" : 之前我们说过可以用服务名直接访问接口,如果我们不想向外界暴露除了application.properties配置映射的服务接口,配置这个属性,只能通过zuul映射的路径访问。
zuul.routes.a.path = /api/a/**
zuul.routes.a.serviceId = springcloud-feign-client
当我们访问zuul服务模块时,只要包含 /api/a/ 路径的服务请求,默认请求到springcloud-ribbon-client模块上的接口
zuul.routes.b.path = /api/b/**
zuul.routes.b.serviceId = springcloud-feign-client
同理,当我们访问zuul服务模块时,只要包含 /api/b/ 路径的服务请求,默认请求到springcloud-feign-client模块上的接口
3. 运行项目
启动 注册中心 springcloud-eureka-server,启动springcloud-ribbon-client服务模块,启动springcloud-feign-client服务模块,启动springcloud-zuul-server模块
在这里首先我要表达歉意,在第一章搭建多模块的微服务项目时,我使用的springcloud和springboot的版本会有问题,所以本章节启动springcloud-zuul-server模块时报错,具体报错如下:

原因是springboot与springcloud的版本不一致导致的,以后有同学遇到同样问题,记得将对应的版本号改成一致
在实际开发过程中,我们详细的版本对应关系:

现在我们将父pom中springcloud的版本号修改为:Greenwich.SR1 ,再启动springcloud-zuul-server服务模块,可以启动成功了,eureka上服务信息如下:

打开浏览器访问访问zuul服务的端口9700:http://localhost:9700/api/a/testzuul?name=young码农,我们发现/api/b/*的请求路由到 springcloud-ribbon-client模块

打开浏览器访问zuul服务的端口9700:http://localhost:9700/api/b/testzuul?name=young码农,我们发现/api/b/*的请求路由到 springcloud-feign-client模块

三、Zuul实现服务过滤:
zuul不仅只是路由,并且还能过滤,可以用来做一些安全验证和日志记录,我写一个简单的接口执行时间记录的功能
新建一个类:BaseZuulFilter
package com.haly.filter; import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; @Component
public class BaseZuulFilter extends ZuulFilter {
protected final Logger logger = LoggerFactory.getLogger(getClass());
// 单例多线程 开始时间绑定在线程上
private ThreadLocal<Long> startTimeThreadLocal = new ThreadLocal<>();
@Override
public String filterType() {
// 在请求被处理之后,会进入该过滤器
return "post";
}
@Override
public int filterOrder() {
return 0;
} @Override
public boolean shouldFilter() {
// 请求开始计时
long startTime = System.currentTimeMillis();
startTimeThreadLocal.set(startTime);
return true;
} @Override
public Object run() {
RequestContext context = RequestContext.getCurrentContext();
String requestURI = String.valueOf(context.get("requestURI")); // 请求结束时间
Long startTime = startTimeThreadLocal.get();
Long endTime = System.currentTimeMillis();
logger.info("[进入zuul日志记录功能] RequestURI:{}, {}:ms", requestURI, endTime - startTime);
return null;
}
}
routing:路由之时
post: 路由之后
error:发送错误调用
shouldFilter:这里可以写逻辑判断,是否要过滤,本文true,永远过滤。
run:过滤器的具体逻辑。可用很复杂,包括查sql,nosql去判断该请求到底有没有权限访问。
四、总结:
当前为止,项目结构:

一起来学Spring Cloud | 第六章:服务网关 ( Zuul)的更多相关文章
- Spring Cloud(六)服务网关 zuul 快速入门
服务网关是微服务架构中一个不可或缺的部分.通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由.均衡负载功能之外,它还具备了权限控制等功能.Spring Cloud Netflix中 ...
- Spring Cloud(七)服务网关 Zuul Filter 使用
上一篇文章中,讲了Zuul 转发,动态路由,负载均衡,等等一些Zuul 的特性,这个一篇文章,讲Zuul Filter 使用,关于网关的作用,这里就不再次赘述了,重点是zuul的Filter ,我们可 ...
- spring cloud深入学习(十一)-----服务网关zuul
前面的文章我们介绍了,Eureka用于服务的注册于发现,Feign支持服务的调用以及均衡负载,Hystrix处理服务的熔断防止故障扩散,Spring Cloud Config服务集群配置中心,似乎一个 ...
- 一起来学Spring Cloud | 第五章:熔断器 ( Hystrix)
在微服务项目中,一个系统可以分割成很多个不同的服务模块,不同模块之间我们通常需要进行相互调用.springcloud中可以使用RestTemplate+Ribbon和Feign来调用(工作中基本都是使 ...
- 一起来学Spring Cloud | 第七章:分布式配置中心(Spring Cloud Config)
上一章节,我们讲解了服务网关zuul,本章节我们从git和本地两种存储配置信息的方式来讲解springcloud的分布式配置中心-Spring Cloud Config. 一.Spring Cloud ...
- Spring Cloud实战之初级入门(六)— 服务网关zuul
目录 1.环境介绍 2.api网关服务 2.1 创建工程 2.3 api网关中使用token机制 2.4 测试 2.5 小结 3.一点点重要的事情 1.环境介绍 好了,不知不觉中我们已经来到了最后一篇 ...
- Spring Cloud 系列之 Gateway 服务网关(二)
本篇文章为系列文章,未读第一集的同学请猛戳这里:Spring Cloud 系列之 Gateway 服务网关(一) 本篇文章讲解 Gateway 网关的多种路由规则.动态路由规则(配合服务发现的路由规则 ...
- Spring Cloud 系列之 Gateway 服务网关(三)
本篇文章为系列文章,未读第一集的同学请猛戳这里: Spring Cloud 系列之 Gateway 服务网关(一) Spring Cloud 系列之 Gateway 服务网关(二) 本篇文章讲解 Ga ...
- Spring Cloud 系列之 Gateway 服务网关(四)
本篇文章为系列文章,未读第一集的同学请猛戳这里: Spring Cloud 系列之 Gateway 服务网关(一) Spring Cloud 系列之 Gateway 服务网关(二) Spring Cl ...
随机推荐
- 【android】6大布局
线性布局 相对布局 绝对布局 网格布局 表格布局 帧布局
- 【laravel】Laravel 5 TokenMismatchException on PHP 5.6.9
When I realized this was only happening in IE and Chrome, but not Firefox, it led me to the fix. The ...
- LeetCode(123) Best Time to Buy and Sell Stock III
题目 Say you have an array for which the ith element is the price of a given stock on day i. Design an ...
- 【HIHOCODER 1589】回文子串的数量(Manacher)
描述 给定一个字符串S,请统计S的所有|S| * (|S| + 1) / 2个子串中(首尾位置不同就算作不同的子串),有多少个是回文字符串? 输入 一个只包含小写字母的字符串S. 对于30%的数据,S ...
- Linux学习-备份的种类、频率与工具的选择
完整备份之累积备份 (Incremental backup) 还原的考虑 如果是完整备份的话.若硬件出问题导致系统损毁时,只要将完整备份拿出来,整个给他倾倒回去硬盘, 所有事情就搞定了!有些时候 (例 ...
- Linux学习-systemctl 针对 timer 的配置文件
如何使用 systemd 内建的 time 来处理各种任务呢? systemd.timer 的优势 在 archlinux 的官网 wiki 上面有提到,为啥要使用 systemd.timer 呢? ...
- Go语言学习03
Go语言-数组类型 一个数组(Array)就是一个可以容纳若干类型相同的元素的容器.这个容器的大小(即数组的长度)是固定的,且是体现在数组的类型字面量之中的.比如,我们声明了一个数组类型: type ...
- poj2449 Remmarguts' Date K短路 A*
K短路裸题. #include <algorithm> #include <iostream> #include <cstring> #include <cs ...
- Codeforces Round #459 (Div. 2)
A. Eleven time limit per test 1 second memory limit per test 256 megabytes input standard input outp ...
- 九度oj 题目1007:奥运排序问题
九度oj 题目1007:奥运排序问题 恢复 题目描述: 按要求,给国家进行排名. 输入: 有多组数据. 第一行给出国家数N,要求排名的国家数M,国家号 ...