SpringCloud使用Zuul構(gòu)建微服務(wù)網(wǎng)關(guān)實踐
SpringCloud 使用Zuul構(gòu)建微服務(wù)網(wǎng)關(guān)
不同的微服務(wù)一般會有不同的網(wǎng)絡(luò)地址,而外部客戶端可能需要調(diào)用多個服務(wù)的接口才能完成一個業(yè)務(wù)需求,如果讓客戶端直接與各個微服務(wù)通信,會有以下問題:
- 客戶端會多次請求不同的微服務(wù),增加了客戶端的復(fù)雜性。
- 存在跨域請求,在一定場景下處理相對復(fù)雜。
- 認證復(fù)雜,每個服務(wù)都需要獨立認證。
- 難以重構(gòu),隨著項目的迭代,可能需要重新劃分微服務(wù)。
- 某些微服務(wù)可能使用了防火墻或瀏覽器不友好協(xié)議,直接訪問會有一定的困難。

為了解決這些問題,需使用微服務(wù)網(wǎng)關(guān)。微服務(wù)網(wǎng)關(guān)是介于客戶端和服務(wù)器端之間的中間層,所有的外部請求都會先經(jīng)過微服務(wù)網(wǎng)關(guān),如圖:

微服務(wù)網(wǎng)關(guān)封裝了應(yīng)用程序的內(nèi)部結(jié)構(gòu),客戶端只跟網(wǎng)關(guān)交互,無需直接調(diào)用特定微服務(wù)的接口,其優(yōu)點:
- 易于監(jiān)控:可在微服務(wù)網(wǎng)關(guān)收集監(jiān)控數(shù)據(jù)并將其推送到外部系統(tǒng)進行分析。
- 易于監(jiān)控:可在微服務(wù)網(wǎng)關(guān)收集監(jiān)控數(shù)據(jù)并將其推送到外部系統(tǒng)進行分析。
- 減少了客戶端和各個微服務(wù)之間的交互次數(shù)。
注意:A服務(wù)和B服務(wù)是可以相互調(diào)用的,作圖的時候忘記了。并且配置服務(wù)也是注冊到服務(wù)注冊中心的。
在Spring Cloud微服務(wù)系統(tǒng)中,一種常見的負載均衡方式是,客戶端的請求首先經(jīng)過負載均衡(zuul、Ngnix),再到達服務(wù)網(wǎng)關(guān)(zuul集群),然后再到具體的服。
服務(wù)統(tǒng)一注冊到高可用的服務(wù)注冊中心集群,服務(wù)的所有的配置文件由配置服務(wù)管理(下一篇文章講述),配置服務(wù)的配置文件放在git倉庫,方便開發(fā)人員隨時改配置。
一、Zuul簡介
Zuul是Netflix開源的微服務(wù)網(wǎng)關(guān),可以和Eureka、Ribbon、Hystrix等組件配合使用,Spring Cloud對Zuul進行了整合與增強,Zuul默認使用的HTTP客戶端是Apache HTTPClient,也可以使用RestClient或okhttp3.OkHttpClient。
Zuul的主要功能是路由轉(zhuǎn)發(fā)和過濾器。路由功能是微服務(wù)的一部分,比如/api/user轉(zhuǎn)發(fā)到到user服務(wù),/api/shop轉(zhuǎn)發(fā)到到shop服務(wù)。zuul默認和Ribbon結(jié)合實現(xiàn)了負載均衡的功能。
Zuul的核心是一系列的過濾器,這些過濾器可以完成以下功能:
- 身份認證與安全:識別每個資源的驗證要求,并拒絕那些與要求不符的請求。
- 審查與監(jiān)控:在邊緣位置追蹤有意義的數(shù)據(jù)和統(tǒng)計結(jié)果,從而帶來精確的生產(chǎn)視圖。
- 動態(tài)路由:動態(tài)地將請求路由到不同的后端集群。
- 壓力測試:逐漸增加指向集群的流量,以了解性能。
- 負載分配:為每一種負載類型分配對應(yīng)容量,并啟用超出限定值的請求。
- 靜態(tài)響應(yīng)處理:在邊緣位置直接建立部分相應(yīng),從而避免其轉(zhuǎn)發(fā)到內(nèi)部集群。
- 多區(qū)域彈性:跨越AWS Region進行請求路由,旨在實現(xiàn)ELB(Elastic Load Balancing)使用的多樣化,以及讓系統(tǒng)的邊緣更貼近系統(tǒng)的使用者。
zuul有以下功能:
- Authentication
- Insights
- Stress Testing
- Canary Testing
- Dynamic Routing
- Service Migration
- Load Shedding
- Security
- Static Response handling
- Active/Active traffic management
二、準備工作
繼續(xù)使用上一節(jié)的工程。在原有的工程上,創(chuàng)建一個新的工程。
三、創(chuàng)建service-zuul工程
其pom.xml文件如下:
<?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.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lijunhao</groupId>
<artifactId>eureka-zuul</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-zuul</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>在其入口applicaton類加上注解@EnableZuulProxy,開啟zuul的功能:
@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class EurekaZuulApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaZuulApplication.class, args);
}
}
加上配置文件application.yml加上以下的配置代碼:
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8080/eureka/
server:
port: 8088
spring:
application:
name: eureka-zuul
zuul:
routes:
api-a:
path: /student/**
serviceId: eureka-student
api-b:
path: /grade/**
serviceId: eureka-grade首先指定服務(wù)注冊中心的地址為http://localhost:8080/eureka/,服務(wù)的端口為8088,服務(wù)名為service-zuul;
以 /student/ 開頭的請求都轉(zhuǎn)發(fā)給 eureka-student 服務(wù);
以 /grade/ 開頭的請求都轉(zhuǎn)發(fā)給 eureka-grade 服務(wù);
依次運行這五個工程;訪問:http://localhost:8088/student/students ;
顯示:

訪問:http://localhost:8088/grade/grades ;
顯示:

這說明zuul起到了路由的作用。
四、服務(wù)過濾
zuul不僅只是路由,并且還能過濾,做一些安全驗證。繼續(xù)改造工程;
創(chuàng)建過濾類:
@Component
public class MyFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(MyFilter.class);
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
Object accessToken = request.getParameter("token");
if(accessToken == null) {
log.warn("token is empty");
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().getWriter().write("token is empty");
}catch (Exception e){}
return null;
}
log.info("ok");
return null;
}
}
filterType:返回一個字符串代表過濾器的類型,在zuul中定義了四種不同生命周期的過濾器類型,具體如下:
- pre:路由之前
- routing:路由之時
- post: 路由之后
- error:發(fā)送錯誤調(diào)用
- filterOrder:過濾的順序
- shouldFilter:這里可以寫邏輯判斷,是否要過濾,本文true,永遠過濾。
- run:過濾器的具體邏輯??捎煤軓?fù)雜,包括查sql,nosql去判斷該請求到底有沒有權(quán)限訪問。
這次訪問:http://localhost:8088/student/students ;
顯示:

訪問 http://localhost:8088/student/students?token=0 ;
網(wǎng)頁顯示:

總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java中控制多線程順序執(zhí)行的六種實現(xiàn)方案
在多線程編程中,線程的執(zhí)行順序本質(zhì)上是不確定的,由操作系統(tǒng)調(diào)度器決定,但在某些業(yè)務(wù)場景中,我們需要確保線程按照特定順序執(zhí)行,所以本文介紹了Java中控制多線程順序執(zhí)行的六種實現(xiàn)方案,需要的朋友可以參考下2025-09-09
解決springboot生成bean名稱沖突(AnnotationBeanNameGenerator)
這篇文章主要介紹了解決springboot生成bean名稱沖突(AnnotationBeanNameGenerator),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
eclipse/intellij idea 查看java源碼和注釋方法
下面小編就為大家?guī)硪黄猠clipse/intellij idea 查看java源碼和注釋方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-05-05
@JsonSerialize(using = LongToStringUtil.class)注解的使
這篇文章主要介紹了@JsonSerialize(using = LongToStringUtil.class)注解的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08
Spring BeanFactory和FactoryBean區(qū)別解析
這篇文章主要介紹了Spring BeanFactory和FactoryBean區(qū)別解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03
Java中動態(tài)設(shè)置JVM參數(shù)的方法總結(jié)
通過動態(tài)設(shè)置JVM參數(shù),開發(fā)者可以更有效地管理資源使用和優(yōu)化性能,本文將詳細闡述如何在Java中動態(tài)設(shè)置JVM參數(shù),感興趣的小伙伴可以了解下2024-12-12
Java開發(fā)工具-scala處理json格式利器-json4s詳解
這篇文章主要介紹了開發(fā)工具-scala處理json格式利器-json4s,文章中處理方法講解的很清楚,有需要的同學(xué)可以研究下2021-02-02

