spring boot 2.0.3+spring cloud (Finchley)5、路由网关Spring Cloud Zuul
Zuul作为微服务系统的网关组件,用于构建边界服务,致力于动态路由、过滤、监控、弹性伸缩和安全。
为什么需要Zuul
Zuul、Ribbon以及Eureka结合可以实现智能路由和负载均衡的功能;网关将所有服务的API接口统一聚合,统一对外暴露。外界调用API接口时,不需要知道微服务系统中各服务相互调用的复杂性,保护了内部微服务单元的API接口;网关可以做用户身份认证和权限认证,防止非法请求操作API接口;网关可以实现监控功能,实时日志输出,对请求进行记录;网关可以实现流量监控,在高流量的情况下,对服务降级;API接口从内部服务分离出来,方便做测试。
Zuul通过Servlet来实现,通过自定义的ZuulServlet来对请求进行控制。核心是一系列过滤器,可以在Http请求的发起和响应返回期间执行一系列过滤器。Zuul采取了动态读取、编译和运行这些过滤器。过滤器之间不能直接通信,而是通过RequestContext对象来共享数据,每个请求都会创建一个RequestContext对象。
Zuul生命周期如下图。 当一个客户端Request请求进入Zuul网关服务时,网关先进入”pre filter“,进行一系列的验证、操作或者判断。然后交给”routing filter“进行路由转发,转发到具体的服务实例进行逻辑处理、返回数据。当具体的服务处理完成后,最后由”post filter“进行处理,该类型的处理器处理完成之后,将Request信息返回客户端。

搭建Zuul服务
需要配置好eureka,ribbon,可参考:
spring boot 2.0.3+spring cloud (Finchley)1、搭建Eureka 以及构建高可用Eureka Server集群
spring boot 2.0.3+spring cloud (Finchley)2、搭建负载均衡Ribbon (Eureka+Ribbon+RestTemplate)
spring boot 2.0.3+spring cloud (Finchley)3、声明式调用Feign
新建工程eureka-zuul-client,pom文件引入相关依赖,包括主maven工程的pom文件,eureka client起步依赖,Zuul的起步依赖,web的起步依赖(已在主maven工程pom中配置)。
<?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> <groupId>com.cralor</groupId>
<artifactId>eureka-zuul-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <name>eureka-zuul-client</name>
<description>Demo project for Spring Boot</description> <parent>
<groupId>com.cralor</groupId>
<artifactId>chap9-zuul</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>
在启动类加上注解@EnableZuulProxy
@EnableZuulProxy
@SpringBootApplication
public class EurekaZuulClientApplication { public static void main(String[] args) {
SpringApplication.run(EurekaZuulClientApplication.class, args);
}
}
在配置文件做相关配置,包括端口号5000,服务注册中心地址http://localhost:8761/eureka/,程序名service-zuul,其中zuul路由配置:zuul.routes.hiapi为”/hiapi/**“,zuul.routes.serviceId为”eureka-client“,这两个配置就可以将以”/hiapi“开头的Url路由到eureka-client服务,zuul.routes.hiapi中的”hiapi“是自己定义的需要指定它的path和serviceId,两者配合使用,就可以将指定类型的请求Url路由到指定的serviceId。同理,满足”/ribbonapi“开头的请求Url都会被分发到eureka-ribbon-client,满足”/feignapi“开头的请求Url都会被分发到eureka-feign-client服务。如果服务存在多个实例,zuul会结合ribbon做负载均衡。
server:
port: 5000
spring:
application:
name: service-zuul eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/ zuul:
routes:
hiapi:
path: /hiapi/**
serviceId: eureka-client
ribbonapi:
path: /ribbonapi/**
serviceId: eureka-ribbon-client
feignapi:
path: /feignapi/**
serviceId: eureka-feign-client
依次启动工程eureka-server、eureka-client(启动两个实例端口为8762、8763)、eureka-ribbon-client、eureka-feign-client和eureka-zuul-client。浏览器多次访问http://localhost:5000/hiapi/hi?name=cralor,会交替显示

可见zuul在路由转发做了负载均衡。同理多次访问http://localhost:5000/ribbonapi/hi?name=cralor和http://localhost:5000/feignapi/hi?name=cralor也可以看到类似内容。
在Zuul上配置API接口的版本号
如果想给每个服务的API接口加前缀,可使用zuul.prefix配置,例如http://localhost:5000/v1/hiapi/hi?name=cralor,即在所有的API接口上加一个v1作为版本号。
zuul:
prefix: /v1
routes:
hiapi:
path: /hiapi/**
serviceId: eureka-client
ribbonapi:
path: /ribbonapi/**
serviceId: eureka-ribbon-client
feignapi:
path: /feignapi/**
serviceId: eureka-feign-client
重启eureka-zuul-client,访问http://localhost:5000/v1/hiapi/hi?name=cralor,结果如上。
在Zuul上配置熔断器
Zuul作为Netflix组件,可以与Ribbon、Eureka和Hystrix等组件相结合,实现负载均衡、熔断器的功能。默认情况下Zuul和Ribbon相结合,实现了负载均衡。实现熔断器功能需要实现FallbackProvider接口,实现该接口的两个方法,一个是getRoute(),用于指定熔断器功能应用于哪些路由的服务;另一个方法fallbackResponse()为进入熔断器功能时执行的逻辑。
@Component
public class MyFallbackProvider implements FallbackProvider {
@Override
public String getRoute() {
return "eureka-client";
} @Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
System.out.println("route:"+route);
System.out.println("exception:"+cause.getMessage());
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
} @Override
public int getRawStatusCode() throws IOException {
return 200;
} @Override
public String getStatusText() throws IOException {
return "ok";
} @Override
public void close() { } @Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("oooops!error,i'm the fallback.".getBytes());
} @Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}
重启eureka-zuul-client,关闭eureka-client的所有实例,访问http://localhost:5000/v1/hiapi/hi?name=cralor,浏览器显示

如果需要所有的路由服务都加熔断功能,需要在getRoute()方法上返回”*“的匹配符
@Override
public String getRoute() {
return "*";
}
在Zuul使用过滤器
Zuul包括以下4中过滤器
PRE过滤器:是在请求路由到具体服务之前执行的,可以做安全验证,如身份验证,参数验证。
ROUTING过滤器:它用于将请求 路由到具体的微服务实例。默认使用Http Client进行网络请求。
POST过滤器:在请求已被路由到微服务后执行的。可用作收集统计信息、指标,以及将响应传输到客户端。
ERROR过滤器:在其他过滤器发生错误时执行。
zuul中默认实现的filter
| 类型 | 顺序 | 过滤器 | 功能 |
|---|---|---|---|
| pre | -3 | ServletDetectionFilter | 标记处理Servlet的类型 |
| pre | -2 | Servlet30WrapperFilter | 包装HttpServletRequest请求 |
| pre | -1 | FormBodyWrapperFilter | 包装请求体 |
| route | 1 | DebugFilter | 标记调试标志 |
| route | 5 | PreDecorationFilter | 处理请求上下文供后续使用 |
| route | 10 | RibbonRoutingFilter | serviceId请求转发 |
| route | 100 | SimpleHostRoutingFilter | url请求转发 |
| route | 500 | SendForwardFilter | forward请求转发 |
| post | 0 | SendErrorFilter | 处理有错误的请求响应 |
| post | 1000 | SendResponseFilter | 处理正常的请求响应 |
禁用指定的Filter
可以在 application.yml 中配置需要禁用的 filter,格式为zuul.<SimpleClassName>.<filterType>.disable=true。
比如要禁用org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter就设置
zuul:
SendResponseFilter:
post:
disable: true
实现自定义滤器需要继承ZuulFilter,实现ZuulFilter中的抽象方法,包括filterType(),filterOrder()以及IZuulFilter的shouldFilter()和run()方法。filterType()为过滤器类型,有4中类型:pre、post、routing和error。filterOrder()是过滤顺序,它为一个int类型的值,值越小,越早执行该过滤器。shouldFilter()表示是否需要执行该过滤器逻辑,true表示执行,false表示不执行,如果true则执行run()方法。run()方法是具体的过滤的逻辑。本例中检查请求的参数中是否传了token这个参数,如果没有传,则请求不被路由到具体的服务实例,直接返回 响应,状态码为401。
@Component
public class MyFilter extends ZuulFilter { private static Logger log=LoggerFactory.getLogger(MyFilter.class); @Override
public String filterType() {
return "pre"; //定义filter的类型,有pre、route、post、error四种
} @Override
public int filterOrder() {
return 0;//定义filter的顺序,数字越小表示顺序越高,越先执行
} @Override
public boolean shouldFilter() {
return true;//表示是否需要执行该filter,true表示执行,false表示不执行
} @Override
public Object run() throws ZuulException {
//filter需要执行的具体操作
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String token = request.getParameter("token");
System.out.println(token);
if(token==null){
log.warn("token is empty");
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().getWriter().write("token is empty");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
log.info("ok");
return null;
}
}
重启服务,访问http://localhost:5000/v1/hiapi/hi?name=cralor,显示

地址栏输入http://localhost:5000/v1/hiapi/hi?name=cralor&token=ccc,显示

可见,MyFilter这个Bean注入IOC容器后,对请求进行了过滤,并在请求路由转发之前进行了逻辑判断。
案例代码地址:https://github.com/cralor7/springcloud

spring boot 2.0.3+spring cloud (Finchley)5、路由网关Spring Cloud Zuul的更多相关文章
- Quick Guide to Microservices with Spring Boot 2.0, Eureka and Spring Cloud
https://piotrminkowski.wordpress.com/2018/04/26/quick-guide-to-microservices-with-spring-boot-2-0-eu ...
- Spring Boot 2.0正式发布,新特性解读
作者|翟永超 Spring Boot 2.0 来啦,有哪些新特性?升级吗? 写在前面 北京时间 3 月 1 日,经过漫长的等待之后,Spring Boot 2.0 正式发布.作为 Spring 生态中 ...
- 重磅:Spring Boot 2.0 正式发布!
Spring Boot 2.0 正式发布! 2018/03/01最新消息,传得沸沸扬扬的Spring Boot 2.0 正式发布了. 小编去看了下Spring Boot的官网,正式版本已经释放出来了! ...
- Spring Boot 2.0 返回JSP页面实战
1. 模板引擎JSP的限制 在开始之前呢,我觉得我们有必要先去了解下 Spring Boot 2.0 官方文档中提到的如下内容: 模板引擎 除了REST Web服务之外,还可以使用Spring MVC ...
- Spring Boot 2.0系列文章(五):Spring Boot 2.0 项目源码结构预览
关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/04/15/springboot2_code/ 项目结构 结构分析: Spring-boot-pr ...
- Spring Boot 2.0系列文章(七):SpringApplication 深入探索
关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/04/30/springboot_SpringApplication/ 前言 在 Spring B ...
- spring boot 2.0 源码分析(一)
在学习spring boot 2.0源码之前,我们先利用spring initializr快速地创建一个基本的简单的示例: 1.先从创建示例中的main函数开始读起: package com.exam ...
- Spring Boot 2.0 迁移指南
3、声明式调用Feign
Feign受Retrofix.JAXRS-2.0和WebSocket影响,采用了声明式API接口的风格,将Java Http客户端绑定到他的内部.Feign的首要目标是将Java Http客户端调用过 ...
随机推荐
- Scrum立会报告+燃尽图(Beta阶段第二周第三次)
此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2411 项目地址:https://coding.net/u/wuyy694 ...
- Alpha阶段第2周/共2周 Scrum立会报告+燃尽图 03
此次作业要求参见https://edu.cnblogs.com/campus/nenu/2018fall/homework/2286 Scrum master:范洪达 一.小组介绍 组长:王一可 组员 ...
- 软工1816 · BETA 版冲刺前准备
任务博客 组长博客 总的来讲Alpha阶段我们计划中的工作是如期完成的.不过由于这样那样的原因,前后端各个任务完成度不算非常高,距离完成一个真正好用.完美的软件还有所差距. 过去存在的问题 测试工作未 ...
- DNS测试工具的使用(了解)
dig命令, host命令, nslookup命令,rndc命令 dig命令(直接测试DNS性能,不会查询/etc/hosts文件) dig [-t RR_TYPE] name [@SERVER] [ ...
- WordPress使用淘宝IP地址库的API显示评论者的位置信息(二)
1 淘宝IP地址库的接口说明 在上一篇文章<WordPress使用淘宝IP地址库的API显示评论者的位置信息(一)>中,vfhky使用了新浪工具提供的这个IP接口显示博客评论者的位置信息. ...
- Filter2D卷积运算
图像处理中的卷积运算一般都用来平滑图像.尖锐图像求边缘等等.主要看你选择什么样的核函数了.现在核函数很多,比如高斯平滑核函数,sobel核函数,canny核函数等等.这里举一个sobel核函数的例子来 ...
- 【bzoj5174】[Jsoi2013]哈利波特与死亡圣器 二分+树形dp
题目描述 给你一棵以1为根的有根树,初始除了1号点为黑色外其余点均为白色.Bob初始在1号点.每次Alice将其中至多k个点染黑,然后Bob移动到任意一个相邻节点,重复这个过程.求最小的k,使得无论B ...
- 表单验证2-JS正则
1. JS正则: 以/开头,以/结尾. test作用:到里面去找,只要里面有,就返回true:否则就返回false. 例如:rep=/\d+/; 检验里面是否有数字. 2.rep=/^ $/; ...
- QT 基本图形绘制
QT 基本图形绘制 1.告诉绘制引擎一些东西 QPainter::Antialiasing 在可能的情况下,反锯齿 QPainter::TextAntialiasing 在可能的情况下,文 ...
- sysbench - 单组件式测试工具
1 安装 > ./configure --with-mysql-includes=/usr/local/mysql/include --with-mysql-libs=/usr/local/my ...