springcloud(hoxton.sr3)基础篇:第六章feign声明式服务调用

圣痕道心      2022-05-05     615

关键词:

一、Feign简介

  在前面的文章中可以发现当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下

  那么有没有更好的解决方案呢?答案是确定的有,Netflix已经为我们提供了一个框架:Feign。而Feign则会完全代理HTTP请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。Feign整合了Ribbon和Hystrix,可以让我们不再需要显式地使用这两个组件。

总起来说,Feign具有如下特性:

  • 可插拔的注解支持,包括Feign注解和JAX-RS注解;
  • 支持可插拔的HTTP编码器和解码器;
  • 支持Hystrix和它的Fallback;
  • 支持Ribbon的负载均衡;
  • 支持HTTP请求和响应的压缩。

这看起来有点像我们springmvc模式的Controller层的RequestMapping映射。这种模式是我们非常喜欢的。Feign是用@FeignClient来映射服务的。

 

二、Feign使用搭建

 

  (1) pom.xml引入相关依赖,引入Feign依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- eureka客户端依赖jar包 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- springBoot运维监控,打开eureka健康检查需要的jar依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!-- feign客户端依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

  

  (2) application.yml配置如下:

server:
  port: 8011
spring:
  application:
      name: consumer-movie-feign
#eureka客户端连接配置
eureka:
   client:
      #打开eureka健康检查
      healthcheck:
         enabled: true
      service-url:
      #注册中心地址
         defaultZone: http://user:password123@localhost:8761/eureka
   instance:
      #将ip注册到eureka上
      prefer-ip-address: true
      #微服务向eureka注册实例名${spring.cloud.client.ip-address} 表示ip地址 spring2.0以上为ip-address
      instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${spring.application.instance_id:${server.port}}

  

  (3) 传输对象User类

import java.math.BigDecimal;

public class User {
  private Long id;

  private String username;

  private String name;

  private Short age;

  private BigDecimal balance;

  //序列化传输的时候必须要有空构造方法,不然会出错
  public User() {
  }
  
  getter() & setter()    
}

 

  (4)Feign的@FeignClient(“服务名称”)映射服务调用接口类

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.qxj.cloud.entity.User;

@FeignClient(name="provider-user")
public interface UserFeignClient {
    @RequestMapping(value="/simple/{id}",method=RequestMethod.GET)
    public User findById(@PathVariable("id") Long id); //// 两个坑:1. @GetMapping不支持   2. @PathVariable得设置value
}

 

  (5)controller类注入UserFeignClient这个接口,进行远程服务调用

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.qxj.cloud.entity.User;
import com.qxj.cloud.feign.UserFeignClient;

@RestController
public class MovieController {

    @Autowired
    private UserFeignClient userFeignClient;

    @RequestMapping(value="/movie/{id}",method = RequestMethod.GET,produces="application/json;charset=UTF-8")
    public User findById(@PathVariable Long id) {
        User user = this.userFeignClient.findById(id);
        return user;
    }
}

  

  (6)接着在Feign模块的启动类哪里打上Eureka客户端的注解@EnableEurekaClient和Feign客户端的注解@EnableFeignClients

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
//该注解表明应用既作为eureka实例又为eureka client 可以发现注册的服务
@EnableEurekaClient
@EnableFeignClients
public class ConsumerMovieFeignApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(ConsumerMovieFeignApplication.class, args);
    }
}

 

  启动Eureka微服务,启动provider-user微服务,最后启动consumer-movie-feign微服务,浏览器上输入localhost:8011/movie/3运行结果如下:

 

 

三、Feign使用Hystrix进行服务降级

  (1)在feign中已经集成了Hystrix组件相关的起步依赖,所以我们不需要额外的添加。

  (2)spring cloud 2.x 以上版本feign默认是关闭了Hystrix功能,application.yml配置启动Hystrix功能

#默认的feign功能中,熔断开关是关闭的,所以,熔断器hystrix的开关需要手动打开
feign:
   hystrix:
      enabled: true

  (3)接下来需要在@FeignClient上添加fallback属性配置快速失败处理类。该处理类是feign hystrix的逻辑处理类,还需要继承UserFeignClient

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.qxj.cloud.entity.User;

@FeignClient(name="provider-user",fallback = HystrixUserFeignFallback.class)
public interface UserFeignClient {
    @RequestMapping(value="/simple/{id}",method=RequestMethod.GET)
    public User findById(@PathVariable("id") Long id); //// 两个坑:1. @GetMapping不支持   2. @PathVariable得设置value
}

  (4)HystrixUserFeignFallback服务降级实现类

import org.springframework.stereotype.Component;

import com.qxj.cloud.entity.User;

//@Component注解将Hystrix类交给spring管理
@Component
public class HystrixUserFeignFallback implements UserFeignClient{

    @Override
    public User findById(Long id) {
        User user = new User();
        user.setId(0L);
        return user;
    }

}

   接着我们再把那服务提供模块provider-user模块进行停止,运行结果如下所示:

 

 

 

 

四、使用FallbackFactory检查回退原因

  (1)修改UserFeignClient接口注解@FeignClient使用fallbackFactory属性

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.qxj.cloud.entity.User;

//fallback属性存在时,fallbackFactory会失效
@FeignClient(name="provider-user",/*fallback = HystrixUserFeignFallback.class,*/fallbackFactory = HystrixUserFeignFactory.class)
public interface UserFeignClient {
    @RequestMapping(value="/simple/{id}",method=RequestMethod.GET)
    public User findById(@PathVariable("id") Long id); //// 两个坑:1. @GetMapping不支持   2. @PathVariable得设置value
}

 

 

  (2)HystrixUserFeignFactory实现类

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.qxj.cloud.entity.User;

import feign.hystrix.FallbackFactory;

@Component
public class HystrixUserFeignFactory implements FallbackFactory<UserFeignClient>{

    private static final Logger LOGGER= LoggerFactory.getLogger(HystrixUserFeignFactory.class);
    
    @Override
    public UserFeignClient create(Throwable cause) {
        //捕捉异常
        LOGGER.error("fallback; reason was: {}", cause.getMessage());
        
        //必须返回UserFeignClient(有@FeignClient的接口)的实现类
        return (id) -> {
            User user = new User();
            user.setId(-1L);
            return user;
        };
        
        //必须返回UserFeignClient(有@FeignClient的接口)的实现类
        /*return new UserFeignClient() {
            @Override
            public User findById(Long id) {
                User user = new User();
                user.setId(-1L);
                return user;
            }
            
        };*/
    }

}

  执行结果

 

 

 

 

   控制台打印的异常信息是null

 

 

 

  但实际上错误原因是TimeoutException,如下

 

 五、为Feign单个Client禁用Hystrix

  (1)全局禁用Hystrix,只须在 application.yml 中配置 feign.hystrix.enabled=false 即可

  (2)借助Feign的自定义配置,可轻松为指定名称的Feign客户端禁用Hystrix。

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.qxj.cloud.entity.User;
import com.qxj.cloud.feign.config.FeignDisableHystrixConfiguration;

@FeignClient(name="provider-user",fallback = HystrixUserFeignFallback.class,configuration = FeignDisableHystrixConfiguration.class)
public interface UserFeignClient {
    @RequestMapping(value="/simple/{id}",method=RequestMethod.GET)
    public User findById(@PathVariable("id") Long id); //// 两个坑:1. @GetMapping不支持   2. @PathVariable得设置value
}

  (3)FeignDisableHystrixConfiguration配置类实现

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;

import feign.Feign;

public class FeignDisableHystrixConfiguration {
    @Bean
    @Scope("prototype")
    public Feign.Builder feignBuilder() {
        return Feign.builder();
    }
}

  运行结果,Hystrix已经被关闭

 

springcloud(hoxton.sr3)基础篇:第四章hystrix请求熔断与服务降级

...如果没有隔离措施,当前应用服务就有被拖垮的风险.  SpringCloudNetflixHystrix就是隔离措施的一种实现,可以设置在某种超时或者失败情形下断开依赖调用或者返回指定逻辑,从而提高分布式系统的稳定性.生 查看详情

springcloud(hoxton.sr3)基础篇:第三章eureka集群高可用的认证服务实现与搭建

一、EurekaServer高可用搭建(服务注册中心)1.1MAVEN相关依赖<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.6.RELEASE& 查看详情

seata分布式事务配置示例(代码片段)

确定版本对应|SpringBoot|2.2.5.RELEASE||SpringCloud|Hoxton.SR3||SpringCloudAlibaba|2.2.1.RELEASE|1.新建两个工程order/pay修改pom<dependency><groupId>org.springframework.boot</groupId><artifactId& 查看详情

nacos使用-服务注册中心和配置中心(代码片段)

本例子基于springboot+springcloudalibaba+springcloud,nacos作为服务注册中心和配置中心。简介Nacos是SpringCloudAlibaba的一个组件。致力于发现、配置和管理微服务。Nacos名字:前四个字母分别为Naming和Configuration的前两个字母,最后的s为Service... 查看详情

springcloud基础概念

文章目录SpringCloud基础概念微服务架构与SpringCloud关于Cloud各种组件的停更/升级/替换SpringCloud基础概念微服务架构与SpringCloudSpringCloud这个框架可以把下面的这些东西全部都包起来:服务注册与发现,服务调用,服务熔断,负载均... 查看详情

springcloud3基础知识(扫盲知识)

一springcloud1.1springcloud1.2springcloud的组件1.3版本依赖关系  查看详情

springcloud基础

Springcloud是基于springboot,管理Springboot创建各个微服务应用,注册服务、服务发现注册服务使用eureka搭建eurekaserver启动类加上@EnableEurekaServerapplication.ymlregisterWithEure、fetchRegistry设置为false表明自己server端server:port:8761eureka:instanc 查看详情

springcloud2.0zuul网关路由基础教程

...、启动基础工程1.1、启动【服务注册中心】,工程名称:springcloud-eureka-server参考SpringCloud2.0EurekaServer服务中心基础教程(二)1.2、启动【服务提供者】,工程名称:springcloud-eureka-client参考SpringCloud2.0EurekaClient服务注册基础教程(三)1.... 查看详情

springcloud基础入门

1.环境搭建在开始SpringCloud之前,先看一下一个简单的服务提供者和服务消费者。服务提供者提供一个REST风格的HTTP接口给服务消费者。1.2pom配置实体类packagecom.test.springcloud.provider.pojo;publicclassUser{privateLongid;privateStringusername;//getter... 查看详情

springcloud基础组件完结--第七章

SpringCloud基础组件完结(第六章用的是RestTemplate远程调用,现在讲的是OpenFeign远程调用)第七章SpringCloud-Hello案例开发-Feign-声明式调用7.1Feign声明式调用准备工作:copy之前的cloud-consumer-user模块, 查看详情

springcloud五大组件基础介绍

SpringCloud五大组件基础介绍SpringCloud五大组件介绍1Eureka注册中心2负载均衡Ribbon3Hystrix4Feign5SpringCloudGateway网关SpringCloud五大组件介绍1Eureka注册中心一个网约车的例子:滴滴这样的网约车平台出现了,所有想载客的私家车全... 查看详情

springcloud2.0turbine断路器集群监控基础教程

...、启动基础工程1.1、启动【服务中心】集群,工程名称:springcloud-eureka-server参考SpringCloud2.0EurekaServer服务中心基础教程(二)1.2、启动【服务提供者】集群,工程名称:springcloud-eureka-client参考SpringCloud2.0EurekaClient服务注册基础教程(... 查看详情

springcloud基础教程服务熔断机制(eureka+ribbon+hystrix)

1、启动【服务中心】集群,即EurekaServer参考SpringCloud基础教程(一)服务中心及集群(EurekaServer)2、启动【服务提供者】集群,即EurekaClient参考SpringCloud基础教程(二)服务注册及集群(EurekaClient)3、启动【服务消费者】,即EurekaDiscoveryCli... 查看详情

hystrix熔断(代码片段)

...和服务降级的方式,提高整体应用的容错能力。我使用的SpringCloud版本是Hoxton.SR3线程隔离:Hystrix使用自己的线程池,和主应用服务器线程隔离开来。每个服务都使用独立的线程池。服务降级:优先保证核心服务可用,非核心服... 查看详情

springcloud基础教程

教程http://blog.didispace.com/Spring-Cloud%E5%9F%BA%E7%A1%80%E6%95%99%E7%A8%8B/代码https://gitee.com/didispace/SpringBoot-Learning 查看详情

springcloud基础介绍

SpringCloud基础介绍什么是微服务     “微服务”一词来源于MartinFowler的一篇博文,https://martinfowler.com/articles/microservices.html总结地说下,微服务是系统架构设计上的一种风格,旨在将一个多元化的大系统拆分成一... 查看详情

springcloud知识概括

SpringCloud知识概括SpringCloud基础组件SpringCloud扩展组件SpringCloud分布式事务组件SpringCloud分布式锁组件SpringCloud基础组件提供注册服务的服务器(第一步):-----------------------------pom.xml-----------------------------<?xmlversion&# 查看详情

如何获取要保存到 MDC 的请求标头

...20-10-0418:25:56【问题描述】:我有一个带有spring-cloud-sleuth(Hoxton.SR3)的springboot(2.2.5.RELEASE)项目。我想向包含标头的控制器发送请求,并且此标头为:填充在控制器的跨距行李中(即currentSpan.context().ext 查看详情