上一篇文章,讲述了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(若是该处有错误也但愿各位指正)