Spring Cloud 服务调用之OpenFeign

361 阅读5分钟

一、简介

  • Ribbon介绍了通过RestTemplate实现远程调用的方法。但是该方法没那么方便,不符合程序员的使用习惯。
  • OpenFeign采用了接口调用的方法,非常符合程序员的习惯,远程调用方法就像本地调用一样方便。
  • 官网
  • Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单。
  • 它的使用方法是定义一个服务接口然后在上面添加注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConvertersFeign可以与EurekaRibbon组合使用以支持负载均衡
  • 简单来说,就是Feign封装了Ribbon,将对象使用封装成了接口调用,在使用的时候通过动态代理的方式实现该接口,然后再调用。

二、实验

1. 导包

    <dependencies>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--一般基础通用配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

2. yaml配置文件

  • 值得一提的是,它关闭了自己在注册中心的注册,其他机器是无法发现它们的。
server:
  port: 80
eureka:
  client:
    # 直接关闭自己的注册
    register-with-eureka: false
    service-url:
      defaultZone: http://127.0.0.1:7001/eureka/,http://127.0.0.1:7002/eureka/

3. 主启动类

@SpringBootApplication
@EnableFeignClients  // 开启Feign
public class OrderFeignMain80 {
  public static void main(String[] args) {
    SpringApplication.run(OrderFeignMain80.class, args);
  }
}

4. 业务类

  • 这是远程服务器真实的请求处理方法
@RestController
public class PaymentController {
  @PostMapping("/payment/create")
  CommonResult<Object> create(@RequestBody Payment payment) {
  // 省略
  }

  @ApiOperation("查找payment")
  @GetMapping("/payment/get/{id}")
  CommonResult<Payment> selectById(@PathVariable("id") Long id) {
  // 省略
  }
}
  • 为了远程调用这些方法,需要自己写一个接口。在接口上标一个注解@FeignClient表示这是一个远程调用的接口,并且给出远程调用服务的名称,该名称与在注册中心上注册的服务名相同。接口上面的注解、方法、参数与原来的基本上没什么太大区别。
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface FeignPaymentService {
  @PostMapping("/payment/create")
  CommonResult<Object> create(@RequestBody Payment payment);
  
  @GetMapping("/payment/get/{id}")
  CommonResult<Payment> selectById(@PathVariable("id") Long id);
}

注意:RequestMapping不能RPC调用!!!一定要指定GetMapping/PostMapping之类的

  • 调用接口。调用接口的时候就像调用本地对象一样方便了。
@Slf4j
@RestController
@RequestMapping("/feign")
public class OrderController {
  @Autowired
  FeignPaymentService feignPaymentService;  // 将远程调用接口注入

  @GetMapping("/payment/get/{id}")
  public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
    CommonResult<Payment> result = feignPaymentService.selectById(id);  // 直接调用并获取结果
    log.info("查询 id: " + id + "的结果为:" + result.toString());
    return result;
  }

  @PostMapping("/payment/create")
  public CommonResult createPayment(@RequestBody Payment payment) {
    CommonResult<Object> result = feignPaymentService.create(payment);
    log.info("插入数据:" + payment.toString());
    return result;
  }
 }

5. 负载均衡

  • 自动开启了负载均衡。实际上还是Ribbon的负载均衡,默认还是轮询方式的负载均衡策略。修改策略也和Ribbon的一样。在配置文件中进行修改。
CLOUD-PAYMENT-SERVICE:  # 服务名
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule  # 策略

三、超时控制

  • 除了简单的远程调用之外,Feign还支持超时控制。Feign默认超时等待1s,如果超过了超时时间,就会触发异常,放弃等待。

1. 修改超时时间

  • 可以通过配置文件修改默认的超时时间
#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
  #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ReadTimeout: 5000
  #指的是建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000

四、日志打印功能

  • 可以通过日志打印,监控远程调用的一些信息

1. 配置日志级别

@Configuration
public class FeignConfig {
  @Bean
  Logger.Level feignLoggerLevel() {
    return Logger.Level.FULL;
  }
}
  • NONE:默认的,不显示任何日志;
  • BASIC:仅记录请求方法、URL、响应状态码及执行时间;
  • HEADERS:除了 BASIC 中定义的信息之外,还有请求和响应的头信息;
  • FULL:除了 HEADERS 中定义的信息之外,还有请求和响应的正文及元数据。

2. 修改配置文件

  • 还需要修改Spring Boot的日志级别,开启该接口的日志级别为debug
logging:
  level:
    # feign日志以什么级别监控哪个接口
    com.atguigu.springcloud.service.PaymentFeignService: debug

3. 查看日志

  • 在控制台,可以看到日志输出
2021-05-23 17:28:33.303 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService        : [FeignPaymentService#selectById] ---> GET http://CLOUD-PAYMENT-SERVICE/payment/get/1 HTTP/1.1
2021-05-23 17:28:33.303 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService        : [FeignPaymentService#selectById] ---> END HTTP (0-byte body)
2021-05-23 17:28:33.314 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService        : [FeignPaymentService#selectById] <--- HTTP/1.1 200 (10ms)
2021-05-23 17:28:33.314 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService        : [FeignPaymentService#selectById] connection: keep-alive
2021-05-23 17:28:33.314 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService        : [FeignPaymentService#selectById] content-type: application/json
2021-05-23 17:28:33.314 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService        : [FeignPaymentService#selectById] date: Sun, 23 May 2021 09:28:33 GMT
2021-05-23 17:28:33.314 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService        : [FeignPaymentService#selectById] keep-alive: timeout=60
2021-05-23 17:28:33.315 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService        : [FeignPaymentService#selectById] transfer-encoding: chunked
2021-05-23 17:28:33.315 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService        : [FeignPaymentService#selectById] 
2021-05-23 17:28:33.316 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService        : [FeignPaymentService#selectById] {"code":200,"message":"查询Payment 1 成功!, Port: 8001","data":{"id":1,"serial":"48193048109341"}}
2021-05-23 17:28:33.316 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService        : [FeignPaymentService#selectById] <--- END HTTP (104-byte body)
2021-05-23 17:28:33.320  INFO 22968 --- [p-nio-80-exec-1] l.d.s.controller.OrderController         : 查询 id: 1的结果为:CommonResult(code=200, message=查询Payment 1 成功!, Port: 8001, data=Payment(id=1, serial=48193048109341))