Feign聲明式服務調用
1、Feign 是一個聲明式的 REST 客戶端,它用了基於接口的注解方式,很方便實現客戶端配置。
2、Feign 最初由 Netflix 公司提供,但不支持SpringMVC注解,后由 SpringCloud 對其封裝,支持了SpringMVC注解,讓使用者更易於接受。
Feign 快速入門
一、feign消費方
1、在消費端引入 open-feign 依賴
2、編寫yaml文件
server:
port: 9000
eureka:
instance:
hostname: localhost #主機名
client:
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: feign-consumer #設置當前應用的名稱。將來會在eureka中Application顯示。將來需要使用該名稱獲取路徑
3、編寫Feign調用接口
package com.zxj.consumer.feign;
import com.zxj.consumer.config.FeignLogConfig;
import com.zxj.consumer.domain.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
*
* feign聲明式接口。發起遠程調用的。
*
String url = "http://FEIGN-PROVIDER/goods/findOne/"+id;
Goods goods = restTemplate.getForObject(url, Goods.class);
*
* 1. 定義接口
* 2. 接口上添加注解 @FeignClient,設置value屬性為 服務提供者的 應用名稱
* 3. 編寫調用接口,接口的聲明規則 和 提供方接口保持一致。
* 4. 注入該接口對象,調用接口方法完成遠程調用
*
*/
@FeignClient(value = "FEIGN-PROVIDER")
public interface GoodsFeignClient {
@GetMapping("/goods/findOne/{id}")
public Goods findGoodsById(@PathVariable("id") int id);
}
注意和提供方中的方法保持一致
在消費方啟動類 添加 @EnableFeignClients 注解,開啟Feign功能
二、feign提供方
1、編寫yaml文件,定義服務名,並將服務注冊到eureka中
server:
port: 8001
eureka:
instance:
hostname: localhost #主機名
prefer-ip-address: true #將當前實例的ip注冊到eureka server中。默認是false注冊主機名
ip-address: 127.0.0.1 #設置當前實例的ip
instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port} #設置web控制台現實的實例id
client:
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: feign-provider #設置當前應用的名稱。將來會在eureka中Application顯示,將來需要使用該名稱來獲取路徑
提供方controller
package com.zxj.provider.controller;
import com.zxj.provider.domain.Goods;
import com.zxj.provider.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Goods Controller 服務提供方
*/
@RestController
@RequestMapping("/goods")
public class GoodsController {
@Autowired
private GoodsService goodsService;
@Value("${server.port}")
private int port;
@GetMapping("/findOne/{id}")
public Goods findOne(@PathVariable("id") int id){
Goods goods = goodsService.findOne(id);
goods.setTitle(goods.getTitle() + ":" + port);//將端口號,設置到了 商品標題上
return goods;
}
}
測試調用
三、編寫eureka注冊中心
1、引入依賴包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
2、編寫yaml文件
server:
port: 8761
eureka:
instance:
hostname: localhost #主機名
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka # eureka服務端地址,將來客戶端使用該地址和eureka進行通信
register-with-eureka: false # 是否將自己的路徑 注冊到eureka上。eureka server 不需要的,eureka provider client 需要
fetch-registry: false # 是否需要從eureka中抓取路徑。eureka server 不需要的,eureka consumer client 需要
server:
enable-self-preservation: false # 關閉自我保護機制
eviction-interval-timer-in-ms: 3000 # 檢查服務的時間間隔
3、編寫啟動類
@SpringBootApplication
@EnableEurekaServer
public class EurekaApp {
public static void main(String[] args) {
SpringApplication.run(EurekaApp.class, args);
}
}
這里的feign的提供方應該在前,消費方應該在后
Feign 其他功能 – 超時設置
Feign 底層依賴於 Ribbon 實現負載均衡和遠程調用。
Ribbon默認1秒超時。
超時配置:
ribbon:
ConnectTimeout: 1000 #連接超時時間,毫秒
ReadTimeout: 1000 #邏輯處理超時時間,毫秒
直接在消費端的application.yml配置文件中添加
Feign 其他功能 – 日志記錄
1、Feign 只能記錄 debug 級別的日志信息。
logging:
level:
com.itheima: debug
2、定義Feign日志級別Bean
/*
NONE,不記錄
BASIC,記錄基本的請求行,響應狀態碼數據
HEADERS,記錄基本的請求行,響應狀態碼數據,記錄響應頭信息
FULL;記錄完成的請求 響應數據
*/
@Configuration
public class FeignLogConfig {
@Bean
public Logger.Level level(){
return Logger.Level.FULL;
}
}
3、啟用該Bean:
@FeignClient(configuration = XxxConfig.class)
@FeignClient(value = "FEIGN-PROVIDER",configuration = FeignLogConfig.class)
public interface GoodsFeignClient {
@GetMapping("/goods/findOne/{id}")
public Goods findGoodsById(@PathVariable("id") int id);
}
** Hystrix 熔斷器**
Hystix 是 Netflix 開源的一個延遲和容錯庫,用於隔離訪問遠程服務、第三方庫,防止出現級聯失敗(雪崩)。
雪崩:一個服務失敗,導致整條鏈路的服務都失敗的情形。
A調用B,B調用C,如果c出現問題,接着b和a也會出現問題
Hystrix 概述
Hystix 是 Netflix 開源的一個延遲和容錯庫,用於隔離訪問遠程服務、第三方庫,防止出現級聯失敗(雪崩)。
雪崩:一個服務失敗,導致整條鏈路的服務都失敗的情形。
Hystix 主要功能
隔離
-
線程池隔離
-
信號量隔離
降級: 異常,超時
熔斷
限流
Hystrix 降級
Hystix 降級:當服務發生異常或調用超時,返回默認數據
Hystrix 降級 – 服務提供方
1、在服務提供方,引入 hystrix 依賴
2、定義降級方法
3、使用 @HystrixCommand 注解配置降級方法
4、在啟動類上開啟Hystrix功能:@EnableCircuitBreaker
Hystrix 降級 – 服務消費方
1、feign 組件已經集成了 hystrix 組件。(如果沒有引入feign的依賴則需要引入hystrix 的依賴)
2、定義feign 調用接口實現類,復寫方法,即 降級方法
3、在 @FeignClient 注解中使用 fallback 屬性設置降級處理類。
4、配置開啟 feign.hystrix.enabled = true
注意:如果服務方返回的是降級后的數據,也就是征程的數據了,消費方就不會再出現降級
Hystrix 熔斷
Hystrix 熔斷機制,用於監控微服務調用情況,當失敗的情況達到預定的閾值(5秒失敗20次),會打開斷路器,拒絕所有請求,直到服務恢復正常為止。
熔斷器默認的情況下是開啟的機制
修改提供方的代碼
發現降級了
多刷幾次降級的頁面后發現正常的也降級了
稍等5秒鍾左右又恢復正常了
參數設置
circuitBreaker.sleepWindowInMilliseconds:監控時間
circuitBreaker.requestVolumeThreshold:失敗次數
circuitBreaker.errorThresholdPercentage:失敗率
Hystrix 熔斷監控
Hystrix 提供了 Hystrix-dashboard 功能,用於實時監控微服務運行狀態。
但是Hystrix-dashboard只能監控一個微服務。
Netflix 還提供了 Turbine ,進行聚合監控。
快速入門:
1、創建hystrix-monitor模塊,引入坐標
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<!-- turbine -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<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-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2、配置application.yml文件
spring:
application:
name: hystrix-monitor
server:
port: 8769
turbine:
combine-host-port: true
//#配置需要被監控的服務名稱列表
app-config: hystrix-provider,hystrix-consumer #可以從eureka的頁面中獲取名稱
cluster-name-expression: "'default'"
aggregator:
cluster-config: default
#instanceUrlSuffix: /actuator/hystrix.stream
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
3、 創建啟動類
@SpringBootApplication
@EnableEurekaClient
@EnableTurbine //開啟Turbine 很聚合監控功能
@EnableHystrixDashboard //開啟Hystrix儀表盤監控功能
public class HystrixMonitorApp {
public static void main(String[] args) {
SpringApplication.run(HystrixMonitorApp.class, args);
}
}
4、修改被監控模塊( hystrix-provider和 hystrix-consumer 模塊)
(1)導入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
(2)配置Bean
此處為了方便,將其配置在啟動類中。
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/actuator/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
(3)啟動類上添加注解@EnableHystrixDashboard
@EnableEurekaClient //該注解 在新版本中可以省略
@SpringBootApplication
@EnableCircuitBreaker // 開啟Hystrix功能
@EnableHystrixDashboard // 開啟Hystrix儀表盤監控功能
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class,args);
}
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/actuator/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
5、啟動測試
(1)、啟動服務:
- eureka-server
- hystrix-provider
- hystrix-consumer
- hystrix-monitor
(2)、訪問:
在瀏覽器訪問http://localhost:8769/hystrix/ 進入Hystrix Dashboard界面
界面中輸入監控的Url地址 http://localhost:8769/turbine.stream,監控時間間隔2000毫秒和title,如下圖
- 實心圓:它有顏色和大小之分,分別代表實例的監控程度和流量大小。如上圖所示,它的健康度從綠色、黃色、橙色、紅色遞減。通過該實心圓的展示,我們就可以在大量的實例中快速的發現故障實例和高壓力實例。
- 曲線:用來記錄 2 分鍾內流量的相對變化,我們可以通過它來觀察到流量的上升和下降趨勢。
** Gateway 網關**
網關旨在為微服務架構提供一種簡單而有效的統一的API路由管理方式。
在微服務架構中,不同的微服務可以有不同的網絡地址,各個微服務之間通過互相調用完成用戶請求,客戶端可能通過調用N個微服務的接口完成一個用戶請求。
存在的問題:
客戶端多次請求不同的微服務,增加客戶端的復雜性
認證復雜,每個服務都要進行認證
http請求不同服務次數增加,性能不高
網關就是系統的入口,封裝了應用程序的內部結構,為客戶端提
供統一服務,一些與業務本身功能無關的公共邏輯可以在這里實現,
諸如認證、鑒權、監控、緩存、負載均衡、流量管控、路由轉發等
在目前的網關解決方案里,有Nginx+ Lua、Netflix Zuul 、Spring Cloud Gateway等等
Gateway 網關快速入門
1.搭建網關模塊
2.引入依賴:starter-gateway
3.編寫啟動類
@SpringBootApplication
@EnableEurekaClient
public class ApiGatewayApp {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApp.class, args);
}
}
4.編寫配置文件
server:
port: 80
spring:
application:
name: api-gateway-server
cloud:
# 網關配置
gateway:
# 路由配置:轉發規則
routes: #集合
# id: 唯一標識。默認是一個UUID
# uri: 轉發路徑
# predicates: 條件,用於請求網關路徑的匹配規則
- id: gateway-provider
uri: http://localhost:8001/
predicates:
- Path=/goods/**
5.啟動測試
結果如下圖片所示時表示訪問成功
Gateway 網關路由配置 – 靜態路由
訪問地址固定不變
Gateway 網關路由配置 – 動態路由
引入eureka-client配置
修改uri屬性:uri: lb://服務名稱
Gateway 網關路由配置 – 微服務名稱配置
能夠訪問成功
Gateway 過濾器
Gateway 支持過濾器功能,對請求或響應進行攔截,完成一些通用操作。
Gateway 提供兩種過濾器方式:“pre”和“post”
pre 過濾器,在轉發之前執行,可以做參數校驗、權限校驗、流量監控、日志輸出、協議轉換等。
post 過濾器,在響應之前執行,可以做響應內容、響應頭的修改,日志的輸出,流量監控等。
Gateway 還提供了兩種類型過濾器
GatewayFilter:局部過濾器,針對單個路由
GlobalFilter :全局過濾器,針對所有路由
Gateway 過濾器 – 局部過濾器
1.GatewayFilter 局部過濾器,是針對單個路由的過濾器。
2.在Spring Cloud Gateway 組件中提供了大量內置的局部過濾器,對請求和響應做過濾操作。
3.遵循約定大於配置的思想,只需要在配置文件配置局部過濾器名稱,並為其指定對應的值,就可以讓其生效。
Gateway 過濾器 – 全局過濾器
GlobalFilter 全局過濾器,不需要在配置文件中配置,系統初始化時加載,並作用在每個路由上。
Spring Cloud Gateway 核心的功能也是通過內置的全局過濾器來完成。
自定義全局過濾器步驟:
1.定義類實現 GlobalFilter 和 Ordered接口
2.復寫方法
3.完成邏輯處理
@Component
public class MyFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("自定義全局過濾器執行了~~~");
return chain.filter(exchange);//放行
}
/**
* 過濾器排序
* @return 數值越小 越先執行
*/
@Override
public int getOrder() {
return 0;
}
}
隨便訪問一個頁面成功后