服務消費者(Feign-上)

上一篇文章,講述了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-hellobattcn-feign-hiapp

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 就是咱們傳遞的請求參數

InvocableHandlerMethodInvocableHandlerMethod

feign.Target -> HardCodedTarget 解析出 FeignClient中的 name 造成VIP模式 GET http://battcn-feign-hello/hello?name=Levin HTTP/1.1 而後發送請求

HardCodedTargetHardCodedTarget

feign.SynchronousMethodHandler -> this.client.execute(request, this.options);

第一個就是:feign.Request的一些信息,好比headermethodbodyurl 等一些基本屬性,由於這裏是feign的Request因此咱們servlet中的請求頭是沒法傳遞過來的(下篇會講述這寫小技巧)

第二個就是:connectTimeoutMillis 和 readTimeoutMillis 不少人確定不陌生

SynchronousMethodHandlerSynchronousMethodHandler

經過三面三個步驟,咱們不難看出 Feign 就是解析註解而後發送HTTP(阻斷器,OKHTTP模式留到下篇),有興趣的能夠本身Debug(若是該處有錯誤也但願各位指正)

相關文章
相關標籤/搜索