一塊兒來學Spring Cloud | 第六章:服務網關 ( Zuul) 一塊兒來學Spring Cloud | 第一章 :如何搭建一個多模塊的springcloud項目

本章節,咱們講解springcloud重要組件:微服務網關Zuul。若是有同窗從第一章看到本章的,會發現咱們已經講解了大部分微服務經常使用的基本組件。html

已經講解過的:前端

一塊兒來學Spring Cloud | 第一章 :如何搭建一個多模塊的springcloud項目java

一塊兒來學Spring Cloud | 第二章:服務註冊和發現組件 (Eureka)web

一塊兒來學Spring Cloud | 第三章:服務消費者 (負載均衡Ribbon)spring

一塊兒來學Spring Cloud | 第四章:服務消費者 ( Feign )sql

一塊兒來學Spring Cloud | 第五章:熔斷器 ( Hystrix)apache

本章正在講解的:一塊兒來學Spring Cloud | 第六章:服務網關 ( Zuul)api

下章即將講解的: 一塊兒來學Spring Cloud | 第七章:分佈式配置中心(Spring Cloud Config)跨域

剛入門的同窗,若是把前面這七章都理解清楚,而且本身搭建一遍,在工做中,咱們已經能夠搭建一個最簡單的微服務項目了,我曾經看過一個創業公司,他們使用微服務框架時,就用以上的組件在生產上運行着簡單的後臺業務系統。瀏覽器

1、Zuul簡介:

Zuul是Netflix開源的微服務網關,它能夠和Eureka、Feign、hystrix等組件配合使用,Zuul的核心是一系列過濾器,它主要功能是路由轉發和過濾器。

在實際項目中,一個複雜的業務系統後臺,少則幾十個服務模塊,多則成百上千,隨着業務場景的不斷變動,咱們的系統也會不斷在演變,就會遇到以下的幾個問題:

1.  若是存在跨域請求,多個微服務在必定的場景下處理相對複雜。

2.  客戶端屢次請求不一樣的微服務,增長了客戶端的複雜性。

3.  認證複雜,每一個微服務都須要獨立認證。

4.  難以重構,隨着項目的迭代,可能須要從新劃分微服務。例如,可能將多個微服務合併成一個或者將一個微服務拆分紅多個。若是客戶端直接與微服務通訊,那麼重構將會很能實施。

5.  某些微服務可能使用了防火牆/瀏覽器不友好的協議,直接訪問會有必定困難。

Zuul提供的做用:

1. 提供統一服務入口,微服務對前臺透明

2. 聚合後臺服務,節省流量,提高性能

3. 安全,過濾,流控等API管理功能

4. 提供統一服務出口,解耦

2、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模塊

3、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; } }
 filterType:返回一個字符串表明過濾器的類型,在zuul中定義了四種不一樣生命週期的過濾器類型,具體以下:
 pre:路由以前
 routing:路由之時
 post: 路由以後
 error:發送錯誤調用
 filterOrder:過濾的順序
 shouldFilter:這裏能夠寫邏輯判斷,是否要過濾,本文true,永遠過濾。
 run:過濾器的具體邏輯。可用很複雜,包括查sql,nosql去判斷該請求到底有沒有權限訪問。
 
瀏覽器分別請求zuul服務模塊:http://localhost:9700/api/b/testzuul?name=young碼農,http://localhost:9700/api/b/testzuul?name=young碼農,會打印以下日誌:
2019-05-25 16:41:07.228  INFO 20984 --- [io-9700-exec-10] com.haly.filter.BaseZuulFilter           : [進入zuul日誌記錄功能]請求地址:/testzuul, 耗時0:ms
有興趣的能夠本身參考上面代碼,作一個簡單接口權限驗證的功能。

4、總結:

當前爲止,項目結構:

相關文章
相關標籤/搜索