springCloud(F版)(3)——zuul實現路由轉發、過濾器、負載均衡
前面博文我們通過rest+Ribbon和Feign的方式實現了對生產者的消費(說白了就是轉手呼叫一下server介面),順帶看了一下負載均衡效果。但是我們發現兩種方式呼叫介面的時候如果想呼叫不同的生產者(application.name或者說serviceID)是需要寫死在程式碼裡的,沒有實現方便的路由轉發功能,另外沒有做過濾器校驗等功能,當然你可以自己DIY進去。今天介紹一個springCloud支援的方便的路由閘道器框架Zuul。
下面主要學習實踐一下Zuul專案的搭建、路由轉發功能、過濾器功能、負載均衡功能。
原始碼百度網盤備份:連結:https://pan.baidu.com/s/16p_4VtqMdw6xF1HN_HzvGg 密碼:m4cg
一、建立一個zuul專案
springboot工程我們已經建立了好幾次了,就不贅述了,直接上截圖。
我又放到testSpringCloud這個根路徑下了,主要是想用這個路徑下的父pom.xml檔案,雖然裡面也沒寫什麼有用的東西,但是養成版本統一控制的習慣還是好的。
修改zuul專案的pom.xml檔案
引入spring-cloud-starter-netflix-eureka-client和spring-cloud-starter-netflix-zuul依賴,spring-boot-starter-web這個依賴基本上我這幾個專案裡都有,如果嫌麻煩的話可以放到父pom.xml裡,更懶的話那就直接複製貼上我的pom檔案吧。父pom.xml檔案到我前面的博文裡找。沒有父pom檔案的,parent標籤會報錯哦。
<?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.testzuul</groupId> <artifactId>zuul</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>zuul</name> <description>Demo project for Spring Boot</description> <parent> <groupId>com.springcloud</groupId> <artifactId>testspringcloud</artifactId> <version>0.0.1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <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> </project>
修改**application.java入口類
新增@EnableZuulProxy、 @EnableEurekaClien和 @EnableDiscoveryClient註解就行了。
@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
@EnableDiscoveryClient
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
修改application.properties配置檔案
自己的埠port是8751,下面配置了兩個閘道器分配的方案
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
server.port: 8751
spring.application.name=service-zuul
zuul.routes.client1.path=/client1/**
zuul.routes.client1.service-id=service-client1
zuul.routes.client2.path=/client2/**
zuul.routes.client2.service-id=service-client2
這樣,zuul的訪問url為 http://IP:port/client*/*** 其中ip是localhost或者遠端釋出的伺服器ip,port就是8751,後面client1就指定到service-client1這個生產者叢集,client2就指定到service-client2這個生產者叢集。zuul是整合Ribbon自動負載均衡的。zuul會按照eureka.client.serviceUrl.defaultZone的配置去找註冊中心將自己註冊進去,後面訪問生產者叢集也是依據自己閘道器配置的service-id去匹配註冊中心的application name的。
二、執行工程測試一下閘道器功能
前面博文我們做好了Eureka server註冊中心,生產者springcloudserver*(我們執行的時候通過指令引數配置成service-client1和service-client2兩個服務叢集),現在又做好了zuul閘道器。那麼我們嘗試著搭建下面這樣一個系統結構出來。
埠號我都寫好了,那麼我們分別跑起來看看吧。Eureka server 和springcloudserver*(就是service-client)的原始碼和可執行jar包我都放在百度網盤裡了,連結:https://pan.baidu.com/s/1SGR6I3VZqrrqJO7Mrqj6Ig 密碼:k2fj
啟動Eureka server,cmd到可執行jar包的目錄(eurekaserver的target裡)執行指令:
java -jar eurekaserver-0.0.1-SNAPSHOT.jar --server.port=8761
啟動service-client1和service-client2,cmd到可執行jar包的目錄(springcloudserver1的target裡)執行指令:
(貼上下面指令的話很可能會帶上莫名其妙的字元,強烈建議參考我下面的截圖手敲)
java -jar **.jar --server.port=8762 --spring.application.name=service-client1
--eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
java -jar **.jar --server.port=8763 --spring.application.name=service-client1
--eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
java -jar **.jar --server.port=8764 --spring.application.name=service-client2
--eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
java -jar **.jar --server.port=8765 --spring.application.name=service-client2
--eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
到這,該執行的都執行好了,當然是沒報錯的情況下。瀏覽器輸入Eureka server的視覺化頁面網址看一下注冊情況
http://localhost:8761
這裡可以看到我們的四個生產者都註冊好了,分了兩個服務叢集service-client1和service-client2。
現在我們編譯執行剛剛弄好的zuul,執行前千萬檢查一下配置檔案,Eureka server的配置,自己的埠號。另外回憶一下我們的生產者有一個/hi介面,引數是name(不輸入name引數的話預設是testname)
瀏覽器輸入http://localhost:8751/client1/hi?name=qftest
反覆試幾次可以看到,client1被路由轉發到service-client1(8762和8763)叢集裡,執行時有負載均衡。
瀏覽器輸入http://localhost:8751/client2/hi?name=qftest 再試試client2的路由轉發。
OK,從測試效果看,我們已經實現了通過zuul對client1和client2進行路由轉發,呼叫不同的生產者服務叢集,並且自帶負載均衡。
三、修改工程,學習實踐一下過濾器。
zuul框架其實提供了很多功能,我們剛剛實踐了一下路由轉發,現在嘗試一下過濾器。
新增一個java類 MyFilter 繼承ZuulFilter,原始碼如下
@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() {
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;
}else if(checkToken(accessToken)){
log.info("ok");
return null;
}else{
log.info("error");
return null;
}
}
private boolean checkToken(Object accessToken) {
//這裡新增token校驗程式碼
return true;
}
}
這裡具體的配置可以百度一下ZuulFilter。我只是寫了一個簡單的token過濾,寫了token無論寫啥都通過,沒寫才報錯。
好了,重新編譯執行看看效果:
瀏覽器輸入 http://localhost:8751/client2/hi?name=qftest (其實就是試試不寫token)
瀏覽器輸入 http://localhost:8751/client2/hi?name=qftest&token=test
OK。至此我們對Zuul框架實現路由轉發、過濾器、負載均衡的學習實踐完成。