上一篇文章,講述了Ribbon去作負載請求的服務消費者,本章講述聲明性REST客戶端:Feign的簡單使用方式java
- Feign簡介
Feign是一個聲明式的Web服務客戶端。這使得Web服務客戶端的寫入更加方便 。它具備可插拔註釋支持,包括Feign註釋和JAX-RS註釋。Feign還支持可插拔編碼器和解碼器。Spring Cloud增長了對Spring MVC註釋的支持,並HttpMessageConverters在Spring Web中使用了默認使用的相同方式。Spring Cloud集成了Ribbon和Eureka,在使用Feign時提供負載平衡的http客戶端。web
官方文檔:http://cloud.spring.io/spring-cloud-static/Dalston.SR2/#spring-cloud-feignspring
- 準備工做
1.啓動Consul,全部文章都將以Consul做爲服務註冊中心bootstrap
2.建立 battcn-feign-hello
,battcn-feign-hi
app
battcn-feign-hello
- pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
|
- BattcnFeignHelloApplication.java
1 2 3 4 5 6 7 8
|
@SpringBootApplication @EnableDiscoveryClient public class BattcnFeignHelloApplication {
public static void main(String[] args) { SpringApplication.run(BattcnFeignHelloApplication.class, args); } }
|
建立一個打招呼的的Controllerspring-boot
- HelloController.java
1 2 3 4 5 6 7 8 9 10 11
|
@RestController @RequestMapping("/hello") public class HelloController { @ResponseStatus(HttpStatus.OK) @GetMapping public String findStudentByName(@RequestParam("name") String name) { // TODO:不作具體代碼實現,只打印Log return "輓歌- My Name's" + name; } }
|
- bootstrap.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
server: port: 8765
spring: application: name: battcn-feign-hello cloud: consul: host: localhost port: 8500 enabled: true discovery: enabled: true prefer-ip-address: true
|
訪問:http://localhost:8765/hello?name=Levin源碼分析
結果:輓歌- My Name's Levin
表示咱們第一個服務運行一切正常this
battcn-feign-hi
- pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
|
- BattcnFeignHiApplication.java
1 2 3 4 5 6 7 8 9
|
@EnableDiscoveryClient @EnableFeignClients(basePackages = {"com.battcn.client"}) @SpringBootApplication public class BattcnFeignHiApplication {
public static void main(String[] args) { SpringApplication.run(BattcnFeignHiApplication.class, args); } }
|
- HelloClient.java
建立一個聲明式FeignClient
的接口 HelloClient
編碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
@FeignClient(name = "battcn-feign-hello") public interface HelloClient {
/** * 在新版本中,Feign 已經能夠解析 RestFul 標準的接口API,好比GET POST DELETE PATCH PUT * 舊版中 * @RequestMapping(method = RequestMethod.GET, value = "/hello") * 或者是 * @RequestMapping(method = RequestMethod.POST, value = "/hello") * * 早期文章:http://blog.battcn.com/2017/07/07/springcloud-feign-analysis/ * / @ResponseStatus(HttpStatus.OK) @GetMapping("/hello") String findStudentByName(@RequestParam("name") String name); }
|
- HiController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
@RestController @RequestMapping("/hi") public class HiController {
@Autowired HelloClient helloClient;
@ResponseStatus(HttpStatus.OK) @GetMapping public String find(@RequestParam("name") String name) { // TODO:只是演示Feign調用的方法 return "Hi," + helloClient.findStudentByName(name); } }
|
- bootstrap.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
server: port: 8766
spring: application: name: battcn-feign-hi cloud: consul: host: localhost port: 8500 enabled: true discovery: enabled: true prefer-ip-address: true
|
訪問:http://localhost:8766/hi?name=Levinurl
結果:Hi,輓歌- My Name'sLevin
表示第二個服務(hi)經過FeignClient調用服務(hello)一切正常
- 源碼分析
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(Object... args)
,該方法的 args 就是咱們傳遞的請求參數
InvocableHandlerMethod
feign.Target
-> HardCodedTarget
解析出 FeignClient中的 name 造成VIP模式 GET http://battcn-feign-hello/hello?name=Levin HTTP/1.1
而後發送請求
HardCodedTarget
feign.SynchronousMethodHandler
-> this.client.execute(request, this.options);
第一個就是:feign.Request
的一些信息,好比header
,method
,body
,url
等一些基本屬性,由於這裏是feign的Request因此咱們servlet中的請求頭是沒法傳遞過來的(下篇會講述這寫小技巧)
第二個就是:connectTimeoutMillis
和 readTimeoutMillis
不少人確定不陌生
SynchronousMethodHandler
經過三面三個步驟,咱們不難看出 Feign 就是解析註解而後發送HTTP(阻斷器,OKHTTP模式留到下篇),有興趣的能夠本身Debug(若是該處有錯誤也但願各位指正)