文章目錄
問題引入
在前面的學習中,我們使用了Ribbon的負載均衡功能,大大簡化了遠程調用時的代碼:
String baseurl = "http://user-service/user/" ;
User user = this.restTemplate.getForobject(baseUrl + id, User.class);
但是可能以後需要編寫類似的大量重複代碼,格式基本相同,無非參數不一樣而已,而且例如這裏的user-service服務名稱我們可以通過eureka獲取,但是user這個路徑怎麼知道呢?
Feign就能很好的解決這個遠程調用的問題。
Feign
- 較爲官方的解釋:
Feign是一個聲明性的Web服務客戶端。它使編寫Web服務客戶端變得更容易。feigin是一種模板化,聲明式的http客戶端,feign可以通過註解綁定到接口上來簡化Http請求訪問。與當我們訪問別的服務端口的時候 大部分使用httpclient等請求進行調用不同,在eureka註冊的服務,我們可以使用Feign 聲明接口的形式來進行相關服務的調用,並提供了失敗回退(其實是Hystrix組件的使用)。Feign只是一個便利的rest框架,簡化調用,最後還是通過ribbon在註冊服務器中找到服務實例,然後對請求進行分配。 - 我的理解:
Feign可以把例如上面這樣的遠程請求給隱藏起來,讓別人看不到,看起來好像是在訪問本地服務一樣,有一種僞裝功能。Feign替我們解決這件事的時候,我們也應該去告訴他 請求路徑、請求參數、請求方式、返回結果,仔細想想這四個東西springmvc的註解就可以搞定,我們的controller方法,有@RequestMapping(method屬性)、@PathVariable、return返回值。所以Feign就可以利用springmvc的註解識別這些信息,幫我們遠程調用,不用我們寫。
Feign的使用
引入依賴並啓動
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@EnableFeignClients
@SpringCloudApplication
public class ConsumerApplication {
/*這個也不需要了,註釋掉
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}*/
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class);
}
}
編寫註解類
這個註解類,其實就是Feign的一個客戶端
@FeignClient("user-service")
:這個註解時指定服務名,去eureka拉取服務列表,然後底層利用ribben進行負載均衡挑選任意一個服務。訪問@GetMapping(“user/findById/{id}”)路徑,參數爲id,返回一個User對象的json字符串,全部自動完成。
@FeignClient("user-service")
public interface UserClient {
@GetMapping("user/findById/{id}")
User findByid(@PathVariable("id")Integer id);
}
修改ConsumerController類
ConsumerController是服務調用端的一個controller類。
@RestController
@RequestMapping("/consumer")
@DefaultProperties(defaultFallback = "findByIdFallback")
public class ConsumerController {
@Autowired//注入UserClient
private UserClient userClient;
@GetMapping("{id}")
public User findById(@PathVariable("id")Integer id){
return userClient.findByid(id);
}
//默認fallback方法,不需要再有參數了
public String findByIdFallback(){
return "不好意思!服務器正忙!!!!";
}
}
userClient.findByid(id)
:這樣的調用,是不是像在調用本地的一個方法一樣,但是本質是進行了遠程調用,很優雅。
Feign與負載均衡與服務降級
思考:在上面的代碼中,我們只告訴了服務調用者服務名稱是user-service,並沒有告訴他ip地址,但是他卻能實現訪問服務並調用功能,說明他內部是有負載均衡處理的。
我們看看feign的包依賴,他內部是有ribbon的實現了負載均衡、hystrix實現了服務熔斷和降級的,而且此時我們如果引入了這個Feign,那麼這兩個依賴就不需要在去單獨引入依賴了。
feign與ribbon負載均衡
而且ribbon的負載均衡和以前使用方式是一樣的,Feign還內置了一個超時時長默認1秒鐘。我們可以在application.yml中進行配置。
ribbon:
ConnectionTimeOut: 1000 # 建立連接的超時時長(1秒未建立就超時)
ReadTimeOut: 1000 # 讀取數據超時時長(1秒未讀取就超時)
feign與hystrix熔斷
注意Hystrix在feign中默認是關閉的,我們應該在application.yml中進行開啓。
# 開啓feign的hystrix功能
feign:
hystrix:
enabled: true
需要注意的是,Feign底層在實現熔斷時,沒有走Springcloud提供的方式,之前我們的配置的值是可用的,但是寫法變了,我們需要自己去寫一個熔斷類。
這個類必須實現我們的UserClient接口,並且要注入到容器中。
@Component
public class UserClientFallBack implements UserClient {
@Override
public User findByid(Integer id) {
User user=new User();
user.setId(id);
user.setUsername("用戶查詢異常!!");
return user;
}
}
UserClient類的@FeignClient(value = "user-service",fallback =UserClientFallBack.class )
指定自定義熔斷類。
@FeignClient(value = "user-service",fallback =UserClientFallBack.class )
public interface UserClient {
@GetMapping("user/findById/{id}")
User findByid(@PathVariable("id")Integer id);
}
測試
啓動服務器,測試一下
未關閉前,一切正常。可以查出數據。
關閉服務提供者UserApplication服務器,肯定會出現遠程連接異常,此時就會得到我們自定義的那個熔斷類對應方法返回的信息了。