OpenFeign遠程調用
1、OpenFeign
OpenFeign是一種聲明式、模板化的HTTP客戶端。在Spring Cloud中使用OpenFeign,可以做到使用HTTP請求訪問遠程服務,就像調用本地方法一樣的,開發者完全感知不到這是在調用遠程方法,更感知不到在訪問HTTP請求。
2、Feign與OpenFeign的區別
Feign是Spring Cloud組件中一個輕量級RESTful的HTTP服務客戶端,Feign內置了Ribbon,用來做客戶端負載均衡,去調用服務注冊中心的服務。Feign的使用方式是:使用Feign的注解定義接口,調用接口,就可以調用服務注冊中心的服務。
OpenFeign是Spring Cloud在Feign的基礎上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通過動態代理的方式產生實現類,實現類中做負載均衡并調用其他服務。
說明:springcloud F 及F版本以上 springboot 2.0 以上基本上使用openfeign,openfeign 如果從框架結構上看就是2019年feign停更后出現版本,也可以說大多數新項目都用openfeign ,2018年以前的項目在使用 feign。
Sentinel流量控制
1、Sentinel簡介
Sentinel是阿里開源的項目,提供了流量控制、熔斷降級、系統負載保護等多個維度來保障服務之間的穩定性。
官網:https://github.com/alibaba/Sentinel/wiki
Sentinel主要特性:
2、Sentinel與Hystrix的區別
關于Sentinel與Hystrix的區別見:https://yq.aliyun.com/articles/633786/
總體來說:
Hystrix常用的線程池隔離會造成線程上下切換的overhead比較大;Hystrix使用的信號量隔離對某個資源調用的并發數進行控制,效果不錯,但是無法對慢調用進行自動降級;Sentinel通過并發線程數的流量控制提供信號量隔離的功能;
此外,Sentinel支持的熔斷降級維度更多,可對多種指標進行流控、熔斷,且提供了實時監控和控制面板,功能更為強大。
Sentinel 的所有規則都可以在內存態中動態地查詢及修改,修改之后立即生效。同時 Sentinel 也提供相關 API,供您來定制自己的規則策略。
Sentinel 支持以下幾種規則:流量控制規則、熔斷降級規則、系統保護規則、來源訪問控制規則 和 熱點參數規則。
openFeign整合Sentinel
第一個項目 spring-cloud-alibaba-2021-user
(調用者)
創建項目名為 spring-cloud-alibaba-2021-user
<?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"><parent><artifactId>spring-cloud-alibaba-2021</artifactId><groupId>org.example</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>spring-cloud-alibaba-2021-user</artifactId><dependencies><!-- springweb 啟動依賴 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- nacos 服務注冊發現(客戶端)依賴 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- nacos-config 配置中心依賴 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!--spring-cloud-dependencies 2020.0.0 版本不在默認加載bootstrap.yml 文件,如果需要加載bootstrap 文件需要手動添加依賴--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency><!--openfeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--loadbalancer ,負載均衡,用來替代ribbon的組件 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><!-- sentinel流量控制,必須加上后降級和限流才會生效--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency></dependencies>
</project>
application.yml 內容如下
server:port: 8089
spring:# 后面的bean會覆蓋前面相同名稱的beanmain:allow-bean-definition-overriding: true# 激活Sentinel對Feign的支持,默認為false。必須設為true后sentinel降級才會生效
feign:sentinel:enabled: true
bootstrap.yml 內容如下,bootstrap.yml 文件比 application.yml 先加載,主要用于存放一些不會改變的配置,application.yml 存放一些經常需要改動的配置;
spring:application:name: user-demoprofiles:active: yexindong_activecloud:nacos:discovery:server-addr: chn520.cn:8848 # 服務注冊中心地址namespace: public # 注冊到nacos的名稱空間,默認為publicconfig:prefix: yexindong_nacos_prefixfile-extension: yaml # 指定yaml格式的配置, 必須要放到bootstrao.yml 才會生效,放到application下不會生效server-addr: chn520.cn:8848 #配置中心地址group: DEFAULT_GROUP
父項目的 pom.xml 文件加入modules
<modules><module>spring-cloud-alibaba-2021-user</module></modules>
新建啟動類 UserApp.java
package com.alibaba.cloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients // // 開啟feign遠程調用
public class UserApp {public static void main(String[] args) {SpringApplication.run(UserApp.class, args);}
}
新建controller層 UserController.java
package com.alibaba.cloud.controller;import com.alibaba.cloud.feign.OrderClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RefreshScope // 不重啟即可刷新 nacos配置
@RequestMapping("/user")
public class UserController {// 調用order遠程服務@RequestMapping("/getOrder")public String getOrder(){return orderClient.getOrderById();}
}
遠程調用接口 OrderClient.java
package com.alibaba.cloud.feign;import com.alibaba.cloud.feign.fallback.OrderFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;/*** value : 其他遠程服務的名稱,對應配置文件的 spring.application.name 值* name: 和value功能一樣* path : url前綴,和 @RequestMapping 注解功能類似* fallback : 降級回調的實現類,當被調服務不可用、發生異常或者超時會直接走降級邏輯,返回友好提示*/
@FeignClient(value="order-demo",path = "order",fallback = OrderFallback.class)
public interface OrderClient {@GetMapping("/getOrderById")String getOrderById();
}
添加降級回調類 OrderFallback.java
package com.alibaba.cloud.feign.fallback;import com.alibaba.cloud.feign.OrderClient;
import org.springframework.stereotype.Component;/*** 降級回調類*/
@Component
public class OrderFallback implements OrderClient {public String getOrderById() {return "order服務暫時不可用!!!";}
}
此時 項目結構如下
創建第二個項目 spring-cloud-alibaba-2021-order
(被調者)
新建工程,起名為 spring-cloud-alibaba-2021-order
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"><parent><artifactId>spring-cloud-alibaba-2021</artifactId><groupId>org.example</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>spring-cloud-alibaba-2021-order</artifactId><dependencies><!-- springweb 啟動依賴 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- nacos 服務注冊發現(客戶端)依賴 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- nacos-config 配置中心依賴 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!--spring-cloud-dependencies 2020.0.0 版本不在默認加載bootstrap.yml 文件,如果需要加載bootstrap 文件需要手動添加依賴--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency><!--openfeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--loadbalancer ,負載均衡,用來替代ribbon的組件 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency></dependencies>
</project>
application.yml 內容如下
server:port: 8088
spring:# 后面的bean會覆蓋前面相同名稱的beanmain:allow-bean-definition-overriding: true
bootstrap.yml 內容如下
spring:application:name: order-demoprofiles:active: yexindong_activecloud:nacos:discovery:server-addr: chn520.cn:8848 # 服務注冊中心地址namespace: public # 注冊到nacos的名稱空間,默認為publicconfig:prefix: yexindong_nacos_prefixfile-extension: yaml # 指定yaml格式的配置, 必須要放到bootstrao.yml 才會生效,放到application下不會生效server-addr: chn520.cn:8848 #配置中心地址group: DEFAULT_GROUP
啟動類 OrderApp.java 內容如下
package com.alibaba.cloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients // // 開啟feign遠程調用
public class OrderApp {public static void main(String[] args) {SpringApplication.run(OrderApp.class, args);}
}
controller層 OrderController.java 內容如下
package com.alibaba.cloud.controller;import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RefreshScope // 不重啟即可刷新 nacos配置
@RequestMapping("/order")
public class OrderController {@Value("${cache:default}")private String cache;@RequestMapping("/getOrderById")public String getOrderById(){return "yexindong order" + cache;}
}
此時項目結構如下
修改 nacos 配置,添加 yexindong_nacos_prefix-yexindong_active.yaml
文件
此時會打開新建配置的頁面,
- DataId 輸入:
yexindong_nacos_prefix-yexindong_active.yaml
- 配置格式 選擇:
YAML
- 配置內容 中輸入:
cache: hello openFeign sentinal!!!
` - 點擊 右下角的
發布
按鈕
測試
啟動 OrderApp.java 和 UserApp.java 中的main方法,一會后發現這2個服務已經注冊到nacos了
在瀏覽器輸入 http://localhost:8089/user/getOrder
,可以正常訪問
測試熔斷降級
接下來我們修改一下OrderController.java
中的 getOrderById()
方法,增加一行代碼,System.out.println(1/0);
讓程序在運行中拋出異常,修改后的內容如下
@RequestMapping("/getOrderById")public String getOrderById(){System.out.println(1/0);return "yexindong order" + cache;}
然后重啟 orderApp ,再次訪問 http://localhost:8089/user/getOrder
,發現已經出發了熔斷,返回了falllback 的友好提示
配置 openFeign 日志
有時候我們遇到bug,接口調用失敗、參數沒收到等問題,或者想看看調用性能,就需要配置OpenFeignde的日志了,以此讓openFeign把請求信息輸出來。
OpenFeign提供了日志打印功能,我們可以通過配置來調整日恙級別,從而了解Feign 中 Http請求的細節。
日志級別
- NONE:默認的,不顯示任何日志;
- BASIC:僅記錄請求方法、URL、響應狀態碼及執行時間;
- HEADERS:除了BASIC中定義的信息之外,還有請求和響應的頭信息;
- FULL:除了HEADERS中定義的信息之外,還有請求和響應的正文及元數據;
全局配置
添加 OpenFeignConfig.java
文件,內容如下
package com.alibaba.cloud.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** 全局配置:當使用@Configuration 會將配置作用所有的服務提供方* 局部配置:如果只想針對某一個服務進行配置,就不要加@Configuration*/
@Configuration
public class OpenFeignConfig {/*日志級別:NONE:默認的,不顯示任何日志;BASIC:僅記錄請求方法、URL、響應狀態碼及執行時間;HEADERS:除了BASIC中定義的信息之外,還有請求和響應的頭信息;FULL:除了HEADERS中定義的信息之外,還有請求和響應的正文及元數據;*/@Beanpublic Logger.Level feignLoggerLevel(){return Logger.Level.FULL;}
}
application.yml
加上以下配置
# openfeign配置包下(或指定哪些業務接口)以什么日志級別監聽,springboot的默認日志級別是info,openFeign的日志級別debug就不會輸出,所以需要加上此配置
logging:level:com:alibaba:cloud:feign: debug
重新請求后就可以在控制臺打印日志了;
局部配置:方式一
直接在接口上指定,在@FeignClient
注解加上configuration = OpenFeignConfig.class
屬性
package com.alibaba.cloud.feign;import com.alibaba.cloud.feign.fallback.OrderFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;/*** value : 其他遠程服務的名稱,對應配置文件的 spring.application.name 值* name: 和value功能一樣* path : url前綴,和 @RequestMapping 注解功能類似* fallback : 降級回調的實現類,當被調服務不可用、發生異常或者超時會直接走降級邏輯,返回友好提示*/
@FeignClient(value="order-demo",path = "order",fallback = OrderFallback.class,configuration = OpenFeignConfig.class)
public interface OrderClient {@GetMapping("/getOrderById")String getOrderById();
}
注意:這種方式需要將OpenFeignConfig.java
類的@Configuration
注解去掉,否則會變成全局配置
局部配置:方式二
application.yml 添加以下配置
# openfeign日志局部配置
feign:client:config:order-demo:loggerLevel: basic
超時時間配置
方式一:添加配置類
創建配置類 OpenFeignTimeOutConfig.java
,內容如下
package com.alibaba.cloud.config;import feign.Request;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class OpenFeignTimeOutConfig {/*** 超時時間配置* @return*/@Beanpublic Request.Options options(){// Options 的第一個參數是連接的超時時間(ms),默認值是 2s;第二個是請求處理的超時時間(ms),默認值是 5s。return new Request.Options(5000,10000);}
}
方式二:配置文件修改
application.yml 添加配置
feign:client:config:order-demo:# 配置指定服務連接超時(單位:ms)connectTimeout: 5000# 配置指定服務等待超時(單位:ms)readTimeout: 5000default:# 配置所有服務的連接超時時間(單位:ms)connectTimeout: 5000# 配置所有服務的等待超時時間(單位:ms)readTimeout: 5000
自定義攔截器
全局配置
添加攔截器類CustomFeignInterceptor.java
package com.alibaba.cloud.interceptor;import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Configuration;/*** 自定義feign攔截器*/
@Configuration
public class CustomFeignInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate requestTemplate) {System.out.println("執行openFeign自定義攔截器");}
}
局部配置
如果寫在配置文件中指明了服務,則為具體的服務指定一個或者多個攔截器, 在 application.yml
加入以下內容
# 在配置文件中設置feign攔截器
feign:client:config:order-demo:# openFeign攔截器requestInterceptors[0]: com.alibaba.cloud.interceptor.CustomFeignInterceptor
再次請求http://127.0.0.1:8089/user/getOrder
發現已經打印了攔截器的內容