springcloud-feign元件實現宣告式的呼叫
11.使用feign實現宣告式的呼叫
使用RestTemplate+ribbon已經可以完成對服務端負載均衡的呼叫,為什麼還要使用feign?
@RequestMapping("/hi")
public String hi(String name) {
String restTemplateForObject = restTemplate.getForObject("http://HI-SERVICE/test/test?name=" + name, String.class);
return restTemplateForObject;
}
上述程式碼採用url拼接引數的形式傳送請求,如果要傳送多個請求引數那麼程式碼就會變得很低效並且難以維護。例如
http://localhost:8762/hi/hi?name=dd&password=123456&age=18
如果使用字串拼接的方式,那麼程式碼可以編排為:
@RequestMapping("/hi") public String hi(String name, String password, Integer age) { Map<Object, Object> map = new HashMap<>(); map.put("name", name); map.put("password", password); map.put("age", age); String restTemplateForObject = restTemplate.getForObject("http://HI-SERVICE/test/test?name={name}&password={password}&age={age}", String.class, map); return restTemplateForObject; }
在這裡url僅僅包含三個引數,如果url為10個引數那麼程式碼會變的更加難以維護。
1.feign簡介
Feign是一個宣告式的偽Http客戶端,它使得寫Http客戶端變得更簡單。使用Feign,只需要建立一個介面並注入。它具有可插拔的註解特性(可以使用springmvc的註解),可使用Feign 註解和JAX-RS註解。Feign支援可插拔的編碼器和解碼器。Feign預設集成了Ribbon,並和Eureka結合,預設實現了負載均衡的效果並且springcloud為feign添加了springmvc註解的支援。
2.為消費者整合feign
1.引入feign的相關依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency>
2.入口類開啟feign支援
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class HiApplication {
public static void main(String[] args) {
SpringApplication.run(HiApplication.class, args);
}
}
3.建立feign介面
@FeignClient(serviceId = "EUREKA-PROVIDER")
public interface feignTest {
@RequestMapping("/test/test")
public String sayHi(String name);
}
建議:feign介面與服務者被呼叫的方法名最好保持一致,呼叫清晰明瞭。
4.控制器
@RequestMapping("/hi")
public String hi(String name) {
final String s = feignTest.sayHi(name);
System.out.println(s);
return s;
}
5.服務者控制器
@RestController
@RequestMapping("/test")
public class TestController {
@RequestMapping("/test1")
public String sayHi(String name){
return "xixixi 8763 :"+name;
}
}
結果:
單引數呼叫是沒有任何問題的。
3.feign日誌
很多的場景下,需要了解feign處理請求的具體細節,如何滿足這種需求呢?
feign對日誌的處理非常靈活可為每個feign客戶端指定日誌記錄策略,每個客戶端都會建立一個logger預設情況下logger的名稱是feign的全限定名需要注意的是,feign日誌的列印只會DEBUG級別做出響應。
我們可以為feign客戶端配置各自的logger.lever物件,告訴feign記錄那些日誌logger.lever有以下的幾種值
- NONE 不記錄任何日誌
- BASIC 僅僅記錄請求方法,url,響應狀態程式碼及執行時間
- HEAdERS 記錄Basic級別的基礎上,記錄請求和響應的header
- FULL 記錄請求和響應的header,body和元資料
1.java配置核心日誌類
@Configuration
public class FeignLogConf {
@Bean
public Logger.Level feignConfiguration() {
return Logger.Level.FULL;
}
}
2.配置feign客戶端的日誌級別
logging.level.com.nyist.feign.FeignLogConf=debug
4.feign構造多引數請求
多引數情況下的feign呼叫會直接報錯,比如兩個String引數feign是無法識別的,必須要引數繫結,我想這就是可插拔註解:RequestParam是springmvc的。
1.錯誤方式
feign的注意事項
1.多引數傳輸的時候 必須要在feign介面上進行引數的繫結
public String testFeign(@RequestParam("name") String name, @RequestParam("password") String password, @RequestParam("age") Integer age);
2.以物件格式為引數進行資料傳輸時 必須設定feign的請求形式為post
3.在服務方接收物件引數時需在形參上加入@RequestBody的註解
public interface feignPost {
@RequestMapping(value = "/test/test1", method = RequestMethod.GET)
public User sayHi(User user);
}
錯誤日誌資訊
feign.FeignException: status 405 reading feignPost#sayHi(User); content:
{"timestamp":1546852876890,"status":405,"error":"Method Not Allowed","exception":"org.springframework.web.HttpRequestMethodNotSupportedException","message":"Request method 'POST' not supported","path":"/test/test1"}
由異常資訊可知,儘管指定了get的方法,feign依然會使用post傳送請求(物件傳輸時)。正確的方式如下:
2.get
@RequestMapping("/test/test",method = RequestMethod.GET)
public String sayHi(@RequestParam("name") String name,@RequestParam("password")String password);
3.post
feign配置
@FeignClient(serviceId = "HI-SERVICE")
public interface feignPost {
@RequestMapping(value = "/test/test1", method = RequestMethod.POST)
public User sayHi(User user);
}
但換個電腦測試時,GET請求是正常的。。。。
服務者
@RequestMapping("/test1")
public User test1(@RequestBody User user) {
return user;
}