• 服务消费者(Feign-上)


    上一篇文章,讲述了Ribbon去做负载请求的服务消费者,本章讲述声明性REST客户端:Feign的简单使用方式

    - Feign简介

    Feign是一个声明式的Web服务客户端。这使得Web服务客户端的写入更加方便 。它具有可插拔注释支持,包括Feign注释和JAX-RS注释。Feign还支持可插拔编码器和解码器。Spring Cloud增加了对Spring MVC注释的支持,并HttpMessageConverters在Spring Web中使用了默认使用的相同方式。Spring Cloud集成了Ribbon和Eureka,在使用Feign时提供负载平衡的http客户端。

    官方文档:http://cloud.spring.io/spring-cloud-static/Dalston.SR2/#spring-cloud-feign

    - 准备工作

    1.启动Consul,所有文章都将以Consul作为服务注册中心

    2.创建 battcn-feign-hellobattcn-feign-hi

    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);
    }
    }

    创建一个打招呼的的Controller

    - 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 表示我们第一个服务运行一切正常

    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=Levin

    结果: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(如果该处有错误也希望各位指正)

  • 相关阅读:
    激活函数
    C++ 三大属性之多态
    C++ 编译运行过程
    优化方法
    目标检测中的IOU
    pytorch 单机多gpu运行
    WSAEventSelect网络模型
    根据数组中的索引删除对应的值
    从以下几点提高服务器并发量
    std::function
  • 原文地址:https://www.cnblogs.com/lywJ/p/10715432.html
Copyright © 2020-2023  润新知