spring cloud 系列第6篇 —— zuul 服务网关 (F版本)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all
一、zuul简介
1.1 API 网关
api 网关是整个微服务系统的门面,所有的外部访问需要通过网关进行调度和过滤。它实现了请求转发、负载均衡、校验过滤、错误熔断、服务聚合等功能。
下图是直观的显示api Gateway 在微服务网关中的作用(图片引用自spring boot 官网)。

1.2 zuul
spring cloud 中提供了基础Net flix Zuul 实现的网关组件,这就是Zuul,它除了实现负载均衡、错误熔断、路由转发等功能,还能与spring 其他组件无缝配合使用。
二、项目结构
spring-cloud-feign用例已经实现通过feign实现服务间的调用,且提供了两个业务服务单元(consumer、producer),可以方便直观的测试zuul的路由、负载均衡、和错误熔断等功能,所以本用例在其基础上进行zuul的整合。
- common: 公共的接口和实体类;
- consumer: 服务的消费者,采用feign调用产品服务;
- producer:服务的提供者;
- eureka: 注册中心;
- zuul: api网关。
聚合项目目录如下:

zuul 项目目录如下:

三、构建api 网关 zuul
3.1 引入依赖
主要的依赖是 spring-cloud-starter-netflix-zuul
<?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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.8.RELEASE</version>
<relativePath/>
</parent>
<artifactId>zuul</artifactId>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--zuul-->
<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>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
3.2 在启动类上添加注解@EnableZuulProxy和@EnableDiscoveryClient
@EnableZuulProxy会自动设置Zuul服务器端点并在其中开启一些反向代理过滤器,以便将请求转发到后端服务器。
@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
3.3 指定注册中心、配置网关的路由规则
zuul 需要指定注册中心的地址,zuul 会从eureka获取其他微服务的实例信息,然后按照指定的路由规则进行请求转发。
server:
port: 8090
# 指定服务命名
spring:
application:
name: zuul
# 指定注册中心地址
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8010/eureka/
# 网关的路由
zuul:
routes:
xxxx: #这个地方的值是可以任意的字符串
path: /producer/**
serviceId: producer
consumer:
path: /consumer/**
serviceId: consumer
3.4 启动eureka、producer、consumer、zuul服务,访问 localhost:8090/consumer/sell/product

四、错误熔断
4.1 zuul 默认整合了 hystrix ,不用导入其他额外依赖

4.2 创建 CustomZuulFallbackProvider并实现FallbackProvider 接口,同时用@Component声明为spring 组件,即可实现熔断时候的回退服务
/**
* @author : heibaiying
* @description : zuul 的熔断器
*/
@Component
public class CustomZuulFallbackProvider implements FallbackProvider {
/*
* 定义熔断将用于哪些路由的服务
*/
@Override
public String getRoute() {
return "consumer";
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
/**
* 返回响应的HTTP状态代码
*/
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.SERVICE_UNAVAILABLE;
}
/**
* 返回HTTP状态代码
*/
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.SERVICE_UNAVAILABLE.value();
}
/**
* 返回响应的HTTP状态文本
*/
@Override
public String getStatusText() throws IOException {
return HttpStatus.SERVICE_UNAVAILABLE.getReasonPhrase();
}
@Override
public void close() {
}
/**
* 将消息正文作为输入流返回
*/
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("商城崩溃了,请稍后重试!".getBytes());
}
/**
* 将消息正文作为输入流返回
*/
@Override
public HttpHeaders getHeaders() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
return httpHeaders;
}
};
}
}
正确返回了内容、同时返回的http状态码也和我们设置的一样。

五、zuul 过滤器
创建自定义过滤器继承自CustomZuulFilter,当我们访问网关的时候,如果判断session 中没有对应的 code,则跳转到我们自定义的登录页面。
/**
* @author : heibaiying
* @description : 自定义filter过滤器
*/
@Component
public class CustomZuulFilter extends ZuulFilter {
/**
* 返回过滤器的类型
*/
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
/**
* 返回过滤器的优先级顺序
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 从此方法返回“true”意味着应该调用下面的 run()方法
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* ZuulFilter的核心校验方法
*/
@Override
public Object run() throws ZuulException {
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
String code = (String)request.getSession().getAttribute("code");
if (StringUtils.isEmpty(code)){
// 设置值为false 不将请求转发到对应的服务上
currentContext.setSendZuulResponse(false);
// 设置返回的状态码
currentContext.setResponseStatusCode(HttpStatus.NON_AUTHORITATIVE_INFORMATION.value());
HttpServletResponse response = currentContext.getResponse();
try {
// 跳转到登录页面
response.sendRedirect("/index");
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
index.ftl:
<!doctype html>
<html lang="en">
<head>
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
<input name="username" type="text">
<button id="btn">输入临时用户名后登录!</button>
</form>
</body>
</html>
六、负载均衡
zuul 默认集成了ribbon 实现了负载均衡。只要启动多个实例即可查看到负载均衡的效果。

这里我们直接在idea 中启动多个实例来测试:

负载均衡测试结果:



七、附:关于版本问题可能导致的 zuul 启动失败
如果出现以下错误导致启动失败,是 spring boot 版本不兼容导致的错误,Finchley SR2版本 spring cloud 中的 zuul 和 spring boot 2.1.x 版本存在不兼容。如果出现这个问题,则将 spring boot 将至 2.0.x 的版本即可,用例中采用的是 2.0.8 版本。在实际的开发中应该严格遵循spring 官方的版本依赖说明。
APPLICATION FAILED TO START
---
Description:
The bean 'counterFactory', defined in class path resource [org/springframework/cloud/netflix/zuul/ZuulServerAutoConfiguration$ZuulCounterFactoryConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/cloud/netflix/zuul/ZuulServerAutoConfiguration$ZuulMetricsConfiguration.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
spring cloud 版本说明:
| Release Train | Boot Version |
|---|---|
| Greenwich | 2.1.x |
| Finchley | 2.0.x |
| Edgware | 1.5.x |
| Dalston | 1.5.x |
更多组件的版本说明可以在spring cloud overview 页面查看。
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all
spring cloud 系列第6篇 —— zuul 服务网关 (F版本)的更多相关文章
- Spring Cloud系列(五):服务网关Zuul
在前面的篇章都是一个服务消费者去调用一个服务提供者,但事实上我们的系统基本不会那么简单,如果真的是那么简单的业务架构我们也没必要用Spring Cloud,直接部署一个Spring Boot应用就够了 ...
- spring cloud 系列第1篇 —— eureka 服务的注册与发现 (F版本)
源码仓库地址:https://github.com/heibaiying/spring-samples-for-all 一.eureka 简介 Spring Cloud Eureka使用Netflix ...
- spring cloud系列教程第一篇-介绍
spring cloud系列教程第一篇-介绍 前言: 现在Java招聘中最常见的是会微服务开发,微服务已经在国内火了几年了,而且也成了趋势了.那么,微服务只是指spring boot吗?当然不是了,微 ...
- Spring cloud系列教程第二篇:支付项目父工程图文搭建
Spring cloud系列教程第二篇:支付项目父工程图文搭建 在讲解spring cloud相关的技术的时候,咱们就模拟订单支付这个流程来讲讲 在这个支付模块微服务搭建过程中,上面的这些技术,都会融 ...
- Spring Cloud系列教程第九篇-Eureka自我保护机制
Spring Cloud系列教程第九篇-Eureka自我保护机制 本文主要内容: 1:自我保护介绍 2:导致原因分析 3:怎么禁止自我保护 本文是由凯哥(凯哥Java:kagejava)发布的< ...
- Spring Cloud系列(一):服务注册中心
一.Spring Cloud简介 Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线).分布式系统的协调导致了样 ...
- Spring Cloud架构教程 (三)服务网关(基础)
通过之前几篇Spring Cloud中几个核心组件的介绍,我们已经可以构建一个简略的(不够完善)微服务架构了.比如下图所示: alt 我们使用Spring Cloud Netflix中的Eureka实 ...
- spring cloud 系列第7篇 —— sleuth+zipkin 服务链路追踪 (F版本)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.简介 在微服务架构中,几乎每一个前端的请求都会经过多个服务单元协调来提 ...
- spring cloud 系列第5篇 —— hystrix+turbine 服务的熔断与监控 (F版本)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.hystrix 简介 1.1 熔断器 在分布式系统中,由于服务之间相互 ...
随机推荐
- sqlserver中获取最后一个字符所在的位置
CHARINDEX('字符',reverse(字段名称)) 这个意思就是将字段进行反转,就是从后往前取,这样就能够获取一个字符最后所在的位置
- 【转】mac版微信web开发者工具(小程序开发工具)无法显示二维码 解决方案
转自:https://www.cnblogs.com/stevenluo/p/6030445.html 微信小程序概念的提出,绝对可以算得上中国IT界惊天动地的一件大事,这可能意味着一场新的开发热 ...
- Method and system for public-key-based secure authentication to distributed legacy applications
A method, a system, an apparatus, and a computer program product are presented for an authentication ...
- ADO.net之2-成功连接到数据库---ShinePans
配置数据库: 连接字符串: server=潘尚\\SQLEXPRESS;database=db_test;Trusted_Connection=true 连接代码: using System; usi ...
- 參数传递(引用,指针,值传递)C++11
C++中,函数的參数传递方式有值传递.地址传递.传地址有指针和引用方式. 在函数參数中,传地址的理由有: 1.使被调函数能够改动主调函数中的数据对象: 2.传地址能够降低数据拷贝,提高程序运行速度. ...
- JPA示例项(J采纳PA的hibernate实现版本号)
(1).JPA介绍: JPA全名Java Persistence API ,Java坚持API这是Sun公司Java EE 5规范中提出的Java持久化接口. JPA吸取了眼下Java持久化技术的长处 ...
- Win32 键盘事件 - 击键消息、字符消息、插入符号(光标)
注:以下内容为学习笔记,多数是从书本.资料中得来,只为加深印象,及日后参考.然而本人表达能力较差,写的不好.因非翻译.非转载,只好选原创,但多数乃摘抄,实为惭愧.但若能帮助一二访客,幸甚! 以下内容主 ...
- WPF中实现PropertyGrid(用于展示对象的详细信息)的三种方式
原文:WPF中实现PropertyGrid(用于展示对象的详细信息)的三种方式 由于WPF中没有提供PropertyGrid控件,有些业务需要此类的控件.这篇文章介绍在WPF中实现PropertyGr ...
- WPF/Silverlight 页面绑定Model验证机制升级版
关于WPF/Silverlight的数据验证,想必大家都不陌生了. 各大牛的博客里都不泛对这方面讨论的文章. 个人比较赞赏 JV9的“Silverlight实例教程”里的Validation数据验证. ...
- C#基础:ref和out的区别 [转]
ref和out的区别在C# 中,既可以通过值也可以通过引用传递参数.通过引用传递参数允许函数成员更改参数的值,并保持该更改.若要通过引用传递参数, 可使用ref或out关键字.ref和out这两个关键 ...