7、Spring Cloud Feign負載與容錯
《SpringBoot整合ribbon專案實戰》一文中介紹了spring cloud的負載均衡和容錯的入門配置,在實際開發中微服務的負載均衡和容錯基本同時出現而且是每個服務不可缺少的一部分。在使用ribbon時,通常會使用resttemplate實現對http請求的封裝,形成了模板化的呼叫方法。spring cloud feign在此基礎上做了進一步的封裝,Feign是一種宣告式、模板化的HTTP客戶端。在Spring Cloud中使用Feign, 我們可以做到使用HTTP請求遠端服務時能與呼叫本地方法一樣的編碼體驗,開發者完全感知不到這是遠端方法,更感知不到這是個HTTP請求。Feign包含了Ribbon和Hystrix,它既能負載也能容錯。
@Autowired
// 遠端服務
private AdvertGropRemoteService service;
public AdvertGroupVO foo(Integer groupId) {
// 通過HTTP呼叫遠端服務
return service.findByGroupId(groupId);
}
接下來,我們在《SpringBoot整合ribbon專案實戰》基礎上搭建一個新的服務消費者customer_feign,其餘服務配置不變,具體步驟如下:
(1)新建專案
在原有的專案不變,在spring-ribbon-eureka專案下建立子專案ribbon_customer_feign,專案型別為jar
(2)修改pom.xml
<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.0http://maven.apache.org/xsd/maven-4.0.0.xsd"> <!-- 專案資訊 --> <modelVersion>4.0.0</modelVersion> <artifactId>ribbon_customer_feign</artifactId> <name>spring cloud feign</name> <description>spring cloud feign</description> <!-- 父專案 --> <parent> <groupId>com.easystudy</groupId> <artifactId>spring-ribbon-eureka</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <!-- 專案強制依賴 --> <dependencies> <!-- spring cloud 客戶註冊 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- spring cloud feign --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> <version>1.4.4.RELEASE</version> </dependency> </dependencies> </project>
(3)新增application.yml配置檔案(在src/main/resources下)
# 多環境通用部分[各個環境可以覆蓋通用欄位]
spring:
application:
# 通用名字,其他環境可以覆蓋:為你的應用起個名字,該名字將註冊到eureka註冊中心
name: ribbon-consumer-feign
server:
# 服務提供監聽埠[eureka客戶端],注意改埠不能與本機伺服器埠衝突
port: 8765
eureka:
client:
# 是否將eureka自身作為應用註冊到eureka註冊中心,預設為true
registerWithEureka: true
service-url:
# 這裡可以填寫所有的eureka伺服器地址並以','分離,當前面不能註冊時候,自動選擇後面的進行註冊,排除單點
注意:修改埠為8765,不要和本機的其他tomcat埠衝突
(4)新增對外的controller,暴露"/hi"介面
package com.easystudy.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.easystudy.service.HelloService;
@RestController
public class CustomerController {
@Autowired
HelloService service;
/**
* 這裡可以像呼叫本地普通方法一樣呼叫遠端過程
* Feign給你的就是不一般的體驗
* @return
*/
@RequestMapping("/hi")
public String customer(){
return service.hello();
}
}
(5)新增HelloService的實現
package com.easystudy.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.easystudy.service.impl.HelloServiceImpl;
/**
* (1)
* @FeignClient註解定義了該介面是一個Feign客戶端,name指定了註冊到Eureka上的服務名,fallback是服務降級後的介面實現類
* 為了讓Feign知道在呼叫方法時應該向哪個地址發請求以及請求需要帶哪些引數,我們需要定義一個介面
* 用於通知Feign元件對該介面進行代理(不需要編寫介面實現),test-service為代理的具體服務
* 這裡的test-service表示service_a和service_b註冊到eureka的服務名
* (2)
* Spring Cloud Feign 的容錯,HystrixCommand定義被封裝起來,沒有辦法通過
* @HystrixCommand註解的fallback,指定服務降級(錯誤處理)方法,Spring Cloud Feign
* 提供也更為簡潔明瞭的方法實現服務降級處理,只需要編寫一個feign介面的具體實現類即可並fallback
* 指定對應降級處理類,Feign的模板化就體現在這裡,通過Feign, 我們能把HTTP遠端呼叫對開發者完全透明,
* 得到與呼叫本地方法一致的編碼體驗
* (3)
* Spring Cloud應用在啟動時,Feign會掃描標有@FeignClient註解的介面,生成代理,並註冊到Spring容器中
* 生成代理時Feign會為每個介面方法建立一個RequetTemplate物件,該物件封裝了HTTP請求需要的全部資訊,
* 請求引數名、請求方法等資訊,如果是在用Spring Cloud Netflix搭建微服務,那麼Feign無疑是最佳選擇
*/
@FeignClient(value="test-service", fallback=HelloServiceImpl.class)
public interface HelloService {
/**
* 對應具體服務中的介面地址,這裡表是service-a和service-b
* 對外提供的具體的介面服務,如com.easystudy.controller.ServiceAController的testA暴露的對外介面"/hello"
* @return
*/
@RequestMapping(value = "/hello", method=RequestMethod.GET)
public String hello();
@RequestMapping(value="/hello2", method=RequestMethod.HEAD)
String hello(@RequestHeader("name") String name,
@RequestHeader("password") String password);
}
(6)新增HelloService降級處理HelloServiceImpl
package com.easystudy.service.impl;
import com.easystudy.service.HelloService;
/**
* Feign容錯降級處理類,它並不是Spring的Service類,
* Feign會掃描標有@FeignClient註解的介面,生成代理
* HelloServiceImpl僅僅是被指定的降級處理類
* @author Administrator
*
*/
public class HelloServiceImpl implements HelloService{
@Override
public String hello() {
return "請求錯誤";
}
/**
* 發現這裡的入參裡我故意去掉了@RequestParam、@RequestBody、@RequestHeader註解,
* 因為這幾個註解本質上的意義就在於Feign在做微服務呼叫的時候對http傳遞引數用的,
* 但服務降級根本不會做http請求了,所以此處可以省略
*/
@Override
public String hello(String name, String password) {
// TODO Auto-generated method stub
return null;
}
}
(7)新增啟動入口RibbonCustomerFeignApp
package com.easystudy;
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 // 通過該註解,實現服務發現,註冊-spring-cloud-commons,支援consul、zookeeper,eureka
//@EnableEurekaClient // 支援eureka,EnableEurekaClient也使用EnableDiscoveryClient註解
@EnableFeignClients // 開啟spring cloud feign的支援,啟動器一定要加@EnableFeignClients,代表進行Feig
public class RibbonCustomerFeignApp {
public static void main(String[] args) {
// TODO Auto-generated method stub
SpringApplication.run(RibbonCustomerFeignApp.class, args);
}
}
(8)測試
啟動eureka_register_service註冊服務,啟動ribbon_service_a和ribbon_service_b都提供test-service的hello服務;啟動客戶端ribbon_customer_feign
再次訪問:
可以看到feign輪訓負載到service_a和service_b提供hello服務;