OpenFeign和Gateway

OpenFeign和Gateway

  • 一.OpenFeign介紹
  • 二.快速上手
    • 1.引入依賴
    • 2.開啟openfeign的功能
    • 3.編寫客戶端
    • 4.修改遠程調用代碼
    • 5.測試
  • 三.OpenFeign參數傳遞
    • 1.傳遞單個參數
    • 2.多個參數、傳遞對象和傳遞JSON字符串
    • 3.最佳方式寫代碼
      • 繼承的方式
      • 抽取的方式
  • 四.部署OpenFeign
  • 五.統一服務入口-Gateway
    • 1.網關
    • 2.常見網關實現
  • 六.快速上手
  • 七.Gateway
    • 1.Predicate
    • 2.Route Predicate Factories
    • 3.Gateway Filter Factories(網關過濾器工廠)
      • GatewayFilter
      • GlobalFilter
      • 過濾器執行順序
      • ?定義過濾器
  • 八.部署Gateway

一.OpenFeign介紹

OpenFeign是?個聲明式的Web Service 客戶端。它讓微服務之間的調?變得更簡單,類似controller
調?service,只需要創建一個接口,然后添加注解即可使?OpenFeign。

OpenFeign的前身:
Feign 是 Netflix 公司開源的一個組件。

  • 2013年6月:Netflix發布 Feign的第一個版本 1.0.0
  • 2016年7月:Netflix發布Feign的最后一個版本 8.18.0
  • 2016年:Netflix 將 Feign 捐獻給社區
  • 2016年7月:OpenFeign 的首個版本 9.0.0 發布,之后一直持續發布到現在.

可以簡單理解為Netflix Feign 是OpenFeign的祖先。或者說OpenFeign 是Netflix Feign的升級版。OpenFeign 是Feign的一個更強大更靈活的實現。

Spring Cloud Feign
Spring Cloud Feign 是 Spring 對 Feign 的封裝,將 Feign 項目集成到 Spring Cloud生態系統中。
受 Feign 更名影響,Spring Cloud Feign 也有兩個 starter

  • spring-cloud-starter-feign
  • spring-cloud-starter-openfeign
    由于Feign的停更維護,對應的,我們使用的依賴是 spring-cloud-starter-openfeign

OpenFeign 官方文檔
Spring Cloud Feign官方文檔

二.快速上手

1.引入依賴

在訂單項目中引入openfeign的依賴:

		<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>

2.開啟openfeign的功能

給訂單項目的啟動類加上openfeign的注解:在這里插入圖片描述

3.編寫客戶端

在訂單服務中寫一個api,value代表微服務的名稱,path代表Feign客戶端的統一前綴
在這里插入圖片描述

4.修改遠程調用代碼

在這里插入圖片描述

5.測試

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

三.OpenFeign參數傳遞

1.傳遞單個參數

ProductController:
在這里插入圖片描述
ProductAPI:在這里插入圖片描述
在Order項目中寫一個FeignController:
在這里插入圖片描述

2.多個參數、傳遞對象和傳遞JSON字符串

ProductController:
在這里插入圖片描述
ProductAPI:
在這里插入圖片描述
FeignController:
在這里插入圖片描述

3.最佳方式寫代碼

繼承的方式

創建一個公共的包來提取公共代碼,創建包的方式和之前相同:

在這里插入圖片描述
再將ProductAPI里面寫的代碼復制到新的ProductAPI項目的包中的,寫成接口的形式:
在這里插入圖片描述

此時需要將ProductInfo引入到這個項目中,但是其他的幾個微服務項目都有這個類于是,可以將這個代碼復制到這個API項目中,其他的微服務項目直接刪除原來的ProductInfo這個類,通過API項目打包的形式放入到起到微服務的POM文件中:

  1. 先進行install,把當前工程打成jar包,放在Maven的本地倉庫
    在這里插入圖片描述

  2. 打包好后對其進行引入后,就會有POM文件自動生成:
    在這里插入圖片描述
    在這里插入圖片描述

  3. 實現接口:
    在這里插入圖片描述

  4. 訂單的微服務中ProductAPI繼承接口:
    在這里插入圖片描述

  5. 使用了ProductInfo和繼承了或者實現了ProductInterface都要將ProductInfo的包重新引入,并對方法進行一些修改。

抽取的方式

  1. 依舊是先建一個module,并在pom文件中引入對應的依賴:在這里插入圖片描述

  2. 將Order微服務的ProductAPI接口放到product-api微服務項目中的api包中,刪除Order原有的api接口:在這里插入圖片描述

  3. 對product-api進行打包:
    在這里插入圖片描述

  4. 啟動服務端

  5. 抽取調用方:在這里插入圖片描述

  6. 進行測試即可

四.部署OpenFeign

對兩個服務進行打包,Maven打包默認是從遠程倉庫下載的,product-api 這個包在本地,有以下解決方案:

  • 上傳到Maven中央倉庫(參考:如何發布Jar包到Maven中央倉庫,比較麻煩)[不推薦]
  • 搭建Maven私服,上傳Jar包到私服 [企業推薦]
  • 從本地讀取Jar包 [個人學習階段推薦]
    前兩種方法比較復雜,咱們使用第三種方式
  1. 從product-api的打包成功后的結果里找到本地Maven路徑寫到Order微服務的POM文件中:
    在這里插入圖片描述
    在這里插入圖片描述
    在這里插入圖片描述
  2. 上傳到云服務器上:
    在這里插入圖片描述
  3. 啟動jar包:
    在這里插入圖片描述

五.統一服務入口-Gateway

1.網關

API網關(簡稱網關)也是?個服務,通常是后端服務的唯一入口。它的定義類似設計模式中的Facade模式(門面模式,也稱外觀模式)。它就類似整個微服務架構的門面,所有的外部客戶端訪問,都需要經過它來進行調度和過濾。

在這里插入圖片描述
網關核心功能:
權限控制: 作為微服務的入口,對用戶進行權限校驗,如果校驗失敗則進行攔截
動態路由: ?切請求先經過網關,但網關不處理業務,而是根據某種規則,把請求轉發到某個微服務
負載均衡:當路由的目標服務有多個時,還需要做負載均衡
限流: 請求流量過高時,按照網關中配置微服務能夠接受的流量進行放行,避免服務壓力過大

2.常見網關實現

業界常用的網關方式有很多,技術方案也較成熟,其中不乏很多開源產品,比如Nginx,Kong,Zuul,
Spring Cloud Gateway等。下面介紹兩種常見的網關方案。

Zuul
Zuul 是 Netflix 公司開源的一個API網關組件,是Spring Cloud Netflix 子項目的核心組件之一,它可以
和 Eureka、Ribbon、Hystrix 等組件配合使用

在Spring Cloud Finchley正式版之前,Spring Cloud推薦的網關是Netflix提供的Zuul(此處指Zuu 1.X).
然而Netflix在2018年宣布一部分組件進入維護狀態,不再進行新特性的開發。這部分組件中就包含Zuul

Spring Cloud Gateway
Spring Cloud Gateway 是Spring Cloud的?個全新的API網關項目,基于Spring + SpringBoot等技術
開發,目的是為了替換掉Zuul。

旨在為微服務架構提供一種簡單而有效的途徑來轉發請求,并為他們提供橫切關注點,比如:安全性,監控/指標和彈性。

在性能方面,根據官方提供的測試報告,Spring Cloud Gateway的RPS(每秒請求數)是Zuul的1.6倍。測
試報告參考

六.快速上手

  1. 創建項目和之前相同
  2. 引入網關的依賴:
<?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.example</groupId><artifactId>spring-cloud-gateway</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>gateway</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency></dependencies></project>
  1. 寫啟動類:
    在這里插入圖片描述
  2. 寫配置信息:
server:port: 10030 # ?關端?
spring:application:name: gateway # 服務名稱cloud:nacos:discovery:server-addr: 1.95.194.117:8848gateway:routes: # ?關路由配置- id: order-service #路由ID, ?定義, 唯?即可uri: lb://order-service #?標服務地址predicates: #路由條件- Path=/order/**,/feign/**- id: product-service #路由ID, ?定義, 唯?即可uri: lb://product-service #?標服務地址predicates: #路由條件- Path=/product/**
  1. 測試
    在這里插入圖片描述

七.Gateway

1.Predicate

Predicate是Java 8提供的一個函數式編程接口,它接收一個參數并返回一個布爾值,用于條件過濾,請求參數的校驗。

代碼:
直接通過實現接口后,調用方法來使用:
在這里插入圖片描述
在這里插入圖片描述
直接是在創建對象的時候重寫方法來使用:在這里插入圖片描述
使用lambda表達式的使用:在這里插入圖片描述

Predicate 的其他方法

  • isEqual(Object targetRef):比較兩個對象是否相等,參數可以為Null
  • and(Predicate other):短路與操作,返回一個組成Predicate
  • or(Predicate other):短路或操作,返回一個組成Predicate
  • test(T t):傳入一個Predicate參數,用來做判斷
  • negate(): 返回表示此Predicate邏輯否定的Predicate
    在這里插入圖片描述

2.Route Predicate Factories

Route Predicate Factories (路由斷言工廠,也稱為路由謂詞工廠,此處謂詞表示一個函數),在Spring
Cloud Gateway中,Predicate提供了路由規則的匹配機制。

我們在配置文件中寫的斷言規則只是字符串,這些字符串會被Route Predicate Factory讀取并處理,轉
變為路由判斷的條件。比如前面章節配置的 Path=/product/** ,就是通過Path屬性來匹配URL前綴是 /product 的請求。

這個規則是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory 來實現的。Spring Cloud Gateway默認提供了很多Route Predicate Factory,這些Predicate會分別匹配HTTP請求的不同屬性,并且多個Predicate可以通過and邏輯進行組合。

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
更多參考

3.Gateway Filter Factories(網關過濾器工廠)

Predicate決定了請求由哪?個路由處理,如果在請求處理前后需要加?些邏輯,這就是Filter(過濾器)的
作用范圍了。

Filter分為兩種類型:Pre類型和Post類型。
Pre類型過濾器:路由處理之前執行(請求轉發到后端服務之前執行),在Pre 類型過濾器中可以做鑒權,限流等。

Post類型過濾器:請求執行?完成后,將結果返回給客戶端之前執行。
在這里插入圖片描述
Spring Cloud Gateway 中內置了很多Filter,用于攔截和鏈式處理web請求。比如權限校驗,訪問超時等設定。
Spring Cloud Gateway從作用范圍上,把Filter可分為GatewayFilter 和GlobalFilter。
GatewayFilter: 應用到單個路由或者一個分組的路由上。
GlobalFilter: 應用到所有的路由上,也就是對所有的請求生效。

GatewayFilter

GatewayFilter 同 Predicate 類似,都是在配置文件 application.yml 中配置,每個過濾器的邏輯都是固定的。比如 AddRequestParameterGatewayFilterFactory 只需要在配置文件中寫AddRequestParameter,就可以為所有的請求添加?個參數,我們先通過?個例子來演示GatewayFilter如何使用。

快速上手:

  1. 添加yml配置
    在這里插入圖片描述
  2. order微服務中添加過濾器參數:在這里插入圖片描述
  3. 通過網管訪問后,日志中打印出userName:在這里插入圖片描述

GatewayFilter詳細介紹官網

Default Filters
前面的filter添加在指定路由下,所以只對當前路由生效,若需要對全部路由生效,可以使用spring.cloud.gateway.default-filters 這個屬性需要?個filter的列表。

yml配置

spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Red, Default-Blue
- PrefixPath=/httpbin

GlobalFilter

lobalFilter是Spring Cloud Gateway中的全局過濾器,它和GatewayFilter的作用是相同的。
GlobalFilter 會應用到所有的路由請求上,全局過濾器通常用于實現與安全性,性能監控和日志記錄等相關的全局功能。
Spring Cloud Gateway 內置的全局過濾器也有很多,比如:

  • Gateway Metrics Filter:網關指標,提供監控指標
  • Forward Routing Filter:用于本地forword,請求不轉發到下游服務器。
  • LoadBalancer Client Filter:針對下游服務,實現負載均衡。
    更多過濾器參考:Global Filters

演示:

  1. 添加依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  1. 添加yml配置
spring:application:name: gateway # 服務名稱cloud:nacos:discovery:server-addr: gateway:metrics:enabled: true
management:endpoints:web:exposure:include: "*"endpoint:health:show-details: alwaysshutdown:enabled: true
  1. 測試
    在這里插入圖片描述

過濾器執行順序

一個項目中,既有GatewayFilter,又有 GlobalFilter時,執行的先后順序是什么呢? 請求路由后,網關會把當前項目中的GatewayFilter和GlobalFilter合并到一個過濾器鏈(集合)中,并進行排序,依次執行過濾器。

在這里插入圖片描述
每一個過濾器都必須指定一個int類型的order值,默認值為0,表示該過濾的優先級。order值越小,優先級越高,執行順序越靠前。

  • Filter通過實現Order接口或者添加@Order注解來指定order值。
  • Spring Cloud Gateway提供的Filter由Spring指定.用戶也可以自定義Filter,由用戶指定。
  • 當過濾器的order值?樣時,會按照 defaultFilter > GatewayFilter > GlobalFilter的順序執行

?定義過濾器

Spring Cloud Gateway提供了過濾器的擴展功能,開發者可以根據實際業務來?定義過濾器,同樣自定
義過濾器也?持GatewayFilter 和 GlobalFilter兩種.

自定義GatewayFilter
自定義GatewayFilter,需要去實現對應的接口 GatewayFilterFactory,Spring Boot 默認幫我們實現的抽象類是 AbstractGatewayFilterFactory,我們可以直接使用。

定義GatewayFilter

  1. 寫一個Custom的Config
    在這里插入圖片描述
  2. 自定義一個CustomGatewayFilterFactory類:在這里插入圖片描述
  3. 增加一點yml的配置:
    在這里插入圖片描述
  4. 測試:
    在這里插入圖片描述

**自定義GlobalFilter **
GlobalFilter的實現比較簡單,它不需要額外的配置,只需要實現GlobalFilter接口,自動會過濾所有的
Filter.

定義GlobalFilter:在這里插入圖片描述

八.部署Gateway

  1. 打包
    在這里插入圖片描述
  2. 把打好的jar包上傳云服務器
  3. 再通過nohup命令啟動jar包

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/76970.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/76970.shtml
英文地址,請注明出處:http://en.pswp.cn/web/76970.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

spark-streaming(二)

DStream創建&#xff08;kafka數據源&#xff09; 1.在idea中的 pom.xml 中添加依賴 <dependency><groupId>org.apache.spark</groupId><artifactId>spark-streaming-kafka-0-10_2.12</artifactId><version>3.0.0</version> </…

JAVA聚焦OutOfMemoryError 異常

個人主頁 文章專欄 在正文開始前&#xff0c;我想多說幾句&#xff0c;也就是吐苦水吧…最近這段時間一直想寫點東西&#xff0c;停下來反思思考一下。 心中萬言&#xff0c;真正執筆時又不知先寫些什么。通常這個時候&#xff0c;我都會隨便寫寫&#xff0c;文風極像散文&…

如何在Spring Boot中配置自定義端口運行應用程序

Spring Boot 應用程序默認在端口 8080 上運行嵌入式 Web 服務器&#xff08;如 Tomcat、Jetty 或 Undertow&#xff09;。然而&#xff0c;在開發、測試或生產環境中&#xff0c;開發者可能需要將應用程序配置為在自定義端口上運行&#xff0c;例如避免端口沖突、適配微服務架構…

linux嵌入式(進程與線程1)

Linux進程 進程介紹 1. 進程的基本概念 定義&#xff1a;進程是程序的一次執行過程&#xff0c;擁有獨立的地址空間、資源&#xff08;如內存、文件描述符&#xff09;和唯一的進程 ID&#xff08;PID&#xff09;。 組成&#xff1a; 代碼段&#xff1a;程序的指令。 數據…

智馭未來:NVIDIA自動駕駛安全白皮書與實驗室創新實踐深度解析

一、引言&#xff1a;自動駕駛安全的范式革新 在當今數字化浪潮的推動下&#xff0c;全球自動駕駛技術正大步邁入商業化的深水區。隨著越來越多的自動駕駛車輛走上道路&#xff0c;其安全性已成為整個行業乃至社會關注的核心命題。在這個關鍵的轉折點上&#xff0c;NVIDIA 憑借…

多模態大模型 Qwen2.5-VL 的學習之旅

Qwen-VL 是阿里云研發的大規模視覺語言模型&#xff08;Large Vision Language Model, LVLM&#xff09;。Qwen-VL 可以以圖像、文本、檢測框作為輸入&#xff0c;并以文本和檢測框作為輸出。Qwen-VL 系列模型性能強大&#xff0c;具備多語言對話、多圖交錯對話等能力&#xff…

Redis 與 Memcache 全面對比:功能、性能與應用場景解析

Redis 和 Memcache 都是常用的內存數據庫&#xff0c;以下是它們在多個方面的能力比較&#xff1a; 一、數據類型 Redis&#xff1a;支持豐富的數據類型&#xff0c;如字符串&#xff08;String&#xff09;、哈希&#xff08;Hash&#xff09;、列表&#xff08;List&#x…

Oracle--PL/SQL編程

前言&#xff1a;本博客僅作記錄學習使用&#xff0c;部分圖片出自網絡&#xff0c;如有侵犯您的權益&#xff0c;請聯系刪除 PL/SQL&#xff08;Procedural Language/SQL&#xff09;是Oracle數據庫中的一種過程化編程語言&#xff0c;構建于SQL之上&#xff0c;允許編寫包含S…

新增優惠券

文章目錄 概要整體架構流程技術細節小結 概要 接口分析 一個基本的新增接口&#xff0c;按照Restful風格設計即可&#xff0c;關鍵是請求參數。之前表分析時已經詳細介紹過這個頁面及其中的字段&#xff0c;這里不再贅述。 需要特別注意的是&#xff0c;如果優惠券限定了使…

力扣面試經典150題(第二十三題)- KMP算法

問題 給你兩個字符串 haystack 和 needle &#xff0c;請你在 haystack 字符串中找出 needle 字符串的第一個匹配項的下標&#xff08;下標從 0 開始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;則返回 -1 。 示例 1&#xff1a; 輸入&#xff1a;haysta…

PostgreSQL 的 MVCC 機制了解

PostgreSQL 的 MVCC 機制了解 PostgreSQL 使用多版本并發控制(MVCC)作為其核心并發控制機制&#xff0c;這是它與許多其他數據庫系統的關鍵區別之一。MVCC 允許讀操作不阻塞寫操作&#xff0c;寫操作也不阻塞讀操作&#xff0c;從而提供高度并發性。 一 MVCC 基本原理 1.1 M…

互聯網大廠Java面試:RocketMQ、RabbitMQ與Kafka的深度解析

互聯網大廠Java面試&#xff1a;RocketMQ、RabbitMQ與Kafka的深度解析 面試場景 面試官&#xff1a;馬架構&#xff0c;您好&#xff01;歡迎參加我們的面試。今天我們將圍繞消息中間件展開討論&#xff0c;尤其是RocketMQ、RabbitMQ和Kafka。您有十年的Java研發和架構設計經…

《巧用DeepSeek快速搞定數據分析》書籍分享

文章目錄 前言內容簡介作者簡介購書鏈接書籍目錄 前言 隨著大數據時代的到來&#xff0c;數據分析和人工智能技術正迅速改變著各行各業的運作方式。DeepSeek作為先進的人工智能模型&#xff0c;不僅在自然語言處理領域具有廣泛應用&#xff0c;還在數據分析、圖像識別、推薦系…

4.Three.js 中 Camera 攝像機詳解

一、什么是 Camera&#xff1f; 在 Three.js 中&#xff0c;Camera&#xff08;攝像機&#xff09;決定了我們如何觀察三維場景。 你可以把它理解為我們“眼睛”的位置和方向&#xff0c;場景中的物體再復雜&#xff0c;如果沒有攝像機&#xff0c;就沒有“觀察角度”&#x…

gem5-gpu教程03 當前的gem5-gpu軟件架構(因為涉及太多專業名詞所以用英語表達)

Current gem5-gpu Software Architecture 這是當前gem5-gpu軟件架構的示意圖。 Ruby是在gem5-gpu上下文中用于處理CPU和GPU之間內存訪問的高度可配置的內存系統 CudaCore (src/gpu/gpgpu-sim/cuda_core.*, src/gpu/gpgpu-sim/CudaCore.py) Wrapper for GPGPU-Sim shader_cor…

負載均衡的實現方式有哪些?

負載均衡實現方式常見的有: 軟件負載均衡、硬件負載均衡、DNS負載均衡 擴展 二層負載均衡&#xff1a;在數據鏈路層&#xff0c;基于MAC地址進行流量分發&#xff0c;較少見于實際應用中 三層負載均衡&#xff1a;在網絡層&#xff0c;基于IP地址來分配流量&#xff0c;例如某…

MyBatis 和 MyBatis-Plus 在 Spring Boot 中的配置、功能對比及 SQL 日志輸出的詳細說明,重點對比日志輸出的配置差異

以下是 MyBatis 和 MyBatis-Plus 在 Spring Boot 中的配置、功能對比及 SQL 日志輸出的詳細說明&#xff0c;重點對比日志輸出的配置差異&#xff1a; 1. MyBatis 和 MyBatis-Plus 核心對比 特性MyBatisMyBatis-Plus定位基礎持久層框架MyBatis 的增強版&#xff0c;提供代碼生…

《數據結構世界的樂高積木:順序表的奇幻旅程》

目錄 1. 線性表 2. 順序表 2.1 概念與結構 2.2 分類 2.2.1 靜態順序表 2.2.2 動態順序表 2.3 動態順序表的實現 1. 線性表 線性表&#xff08;linear list&#xff09;是n個具有相同特性的數據元素的有限序列。線性表是?種在實際中?泛使?的數據結構&#xff0c;常?的…

RHCE 練習二:通過 ssh 實現兩臺主機免密登錄以及 nginx 服務通過多 IP 區分多網站

一、題目要求 1.配置ssh實現A&#xff0c;B主機互相免密登錄 2.配置nginx服務&#xff0c;通過多ip區分多網站 二、實驗 實驗開始前需準備兩臺 linux 主機便于充當服務端以及客戶端&#xff0c;兩臺主機 IP 如下圖&#xff1a; 實驗1&#xff1a;配置 ssh 實現 A&#xff0…

第十五屆藍橋杯 2024 C/C++組 好數

題目&#xff1a; 題目描述&#xff1a; 題目鏈接&#xff1a; 好數 思路&#xff1a; 第一種思路詳解&#xff1a; 因為每次檢查數都是從個位開始&#xff0c;所以對于每一個數都是先檢查奇數位再檢查偶數位&#xff0c;即存在先檢查奇數位再檢查偶數位的循環。注意一次完…