浅谈Spring Cloud OpenFeign

OpenFeign是一种声明式、模板化的HTTP客户端。在Spring Cloud中使用OpenFeign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问HTTP请求。
Spring Cloud OpenFeign以将OpenFeign集成到Spring Boot应用中的方式。首先利用了OpenFeign的声明式方式定义Web服务客户端;其次还更进一步,通过集成Ribbon或Eureka实现负载均衡的HTTP客户端。

OpenFeign 组件的前身是 Netflix Feign 项目。后来 Feign 项目被贡献给了开源组织,才有了今天使用的 Spring Cloud OpenFeign 组件。
OpenFeign 提供了一种声明式的远程调用接口,它可以简化远程调用的编程体验。

在项目启动阶段,OpenFeign 框架会发起一个主动的扫包流程,从指定的目录下扫描并加载所有被 @FeignClient 注解修饰的接口。
OpenFeign 会针对每一个 FeignClient 接口生成一个动态代理对象。
FeignProxyService,这个代理对象在继承关系上属于 FeignClient 注解所修饰的接口的实例。
这个动态代理对象会被添加到 Spring 上下文中,并注入到对应的服务里,也就是图中的 LocalService 服务。
LocalService 会发起底层方法调用。实际上这个方法调用会被 OpenFeign 生成的代理对象接管,由代理对象发起一个远程服务调用,并将调用的结果返回给 LocalService。

Feign底层是ribbon

Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netf1ixRib5实现。通过 Spring C1oud的封装,可以让我们轻松地将面向服务的REST模版请求自动转換成客户端负载均衡的服务调用。轮询hash权重.

简单的说 Ribbon就是 netfix公司的一个开源项目,主要功能是提供客户端负载均衡算法和服务调用。 Ribbon客户端组件提供了一套完善的配置项,比如连接超时,重试等。在 Spring Cloud构建的微服务系统中, Ribbon作为服务消费者的负载均衡器,有两种使用方式,一种是和 Resttemplate相结合,另一种是和 Openfeign相结合。 openfelgn已经默认集成了 Ribbon,关于 Openfeign的内容将会在下一章进行详细讲解。 Ribbon有很多子模块,但很多模块没有用于生产环境

Openfeign快速入门

Provider端

.yml

server:
  port: 8080  
spring:
  application:
    name: provider-server #应用名称

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

User(消费端)

server:
  port: 8081
spring:
  application:
    name: user-server #应用名称

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

#设置超时时间
ribbon:
  ReadTimeout: 3000 # 3秒
  ConnectTimeout: 3000 #连接服务的超时时间

OpenFeign调用参数处理(重点)

@PathVariable注解:获取url中的数据

解决映射名称不一致问题(提交请求参数的action的形参名称不一致,使用@RequestParam注解解析)

Feign传参确保消费者和提供者的参数列表一致包括返回值方法签名要一致

1.通过URL传参数,GET请求,参数列表使用@PathVariable (“”)

2.如果是GET请求,每个基本参数必须加回 @Requestparam(“”)

3.如果是posT请求,而且是对象集合等参数,必须加@ Requestbody或者@ Requestparam

provider-service端

@RestController

public class ParamController {

    //url传参
    @GetMapping("param/{name}/{age}")
    public String param(@PathVariable("name") String name,@PathVariable("age") int age){
        System.out.println("姓名: "+name+" 年龄 "+age);
    return "姓名: "+name+" 年龄 "+age;
    }
    @GetMapping("getParam")
    public String getParam(@RequestParam(required = false) String name){
        System.out.println("姓名: "+name);
        return "姓名: "+name;
    }
    @GetMapping("twoParam")
    public String twoParam(@RequestParam(required = false) String name,@RequestParam(required = false)int age){
        System.out.println("姓名: "+name+" 年龄 "+age);
        return "姓名: "+name+" 年龄 "+age;
    }
    @PostMapping("oneObject")
    public String oneObject(@RequestBody User user){
        System.out.println(user.toString());
        return user + "";
    }

}

User-service端

@FeignClient(value = "provider-server") //提供者的应用名称
public interface UserProviderFeign {

    @GetMapping("provider")
    public String provider();

    @GetMapping("param/{name}/{age}")
    public String paramUrl(@PathVariable("name") String name, @PathVariable("age") int age);

    @GetMapping("getParam")
    public String getParam(@RequestParam(required = false) String name);

    @GetMapping("twoParam")
    public String twoParam(@RequestParam(required = false) String name,@RequestParam(required = false)int age);

    @PostMapping("oneObject")
    public String oneObject(@RequestBody User user);

}

@GetMapping("paramTest")

public String paramTest(){

    userProviderFeign.paramUrl("张三",20);
    userProviderFeign.getParam("李四");
    userProviderFeign.twoParam("小红",18);
    User user = User.builder()
            .name("小冰")
            .age(18)
            .time(new Date()).build();
    userProviderFeign.oneObject(user);
    return "provider";

}

Feign传递时间

@GetMapping("testTime")
public String testTime(@RequestParam Date date){
    return date +"";
}

@GetMapping("time")
public String time(){
Date date =new Date();
    System.out.println(date);
    String s = userProviderFeign.testTime(date);
    return s;

}

Feign日志处理

Feign提供了日志打印功能,我们在项目中可以通过配置来调整日志级别,从而了解Feign中http请求的细节 ,也就是说feign提供的日志功能可以对接口的调用情况进行监控和输出。

日志级别:

NONE: 默认的,不显示任何日志

BASIC:仅记录请求方法、URL、响应状态码以及执行时间

HEADERS:除了BASIC中定义的信息以外,还有请求和响应的头信息

FULL: 除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据

public Logger.Level level(){

    return Logger.Level.FULL;

}

logging:
  level:
    com.example.feign.UserProviderFeign : debug

Hystrix介绍

Hystrix是一个用于处理分布式系统的延迟和容错的一个开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能保证在一个依赖出现问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的稳定性。“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的,可处理的备选响应,而不是长时间等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

provider-service端

application.yml

server:

  port: 8080

spring:

  application:

    name: provider-service01

eureka:

  client:

    service-url:

      defaultZone: http://localhost:8761/eureka

  instance:

    hostname: localhost

    instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}

Customer-service端

添加Hystrix依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

application.yml

server:
  port: 8081
spring:
  application:
    name: c-service
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
  instance:
    hostname: localhost
    instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}

feign:
  hystrix:
    enabled: true 

Feign接口

@FeignClient(value = "provider-service01") //provider服务名
public interface CustomerToProviderFeign {

    @GetMapping("Provider")
    public String pro();
}

@Component
public class CustomerToProviderFeignHystrix implements CustomerToProviderFeign {

    @Override
    public String pro() {
        return "熔断后备选方案";
    }
}

controller

Hystrix常用配置

server:
  port: 8081
spring:
  application:
    name: c-service
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
  instance:
    hostname: localhost
    instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}

feign:
  hystrix:
    enabled: true
hystrix:  #hysrix全局控制
  command:
    default:
      circuitBreaker:
        enabled: true #开启断路器
        requestVolumeThreshold: 10 #失败次数
        sleepWindowInMilliseconds: 20000 #窗口时间
        errorThresholdPercentage: 60 #失败率
      execution:
        isolation:
          Strategy: thread #隔离方式 thread线程格里尼集合和SEMAPHORE信号量隔离级别
          thread:
            timeoutInMilliseconds: 3000 #调用超时时长
      fallback:
        isolation:
          semaphore:
            maxConcurrentRequests: 1000  #信号量隔离级别最大并发数
ribbon:
  ReadTimeout: 5000   #结合feign底层ribbon调用时长
  ConnectTimeout: 5000

OpenFeign项目

eign-project01

Pom.xml

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <maven.compiler.source>8</maven.compiler.source>
  <maven.compiler.target>8</maven.compiler.target>
  <java.version>1.8</java.version>
  <spring-cloud.version>Hoxton.SR12</spring-cloud.version>
</properties>

<dependencies>
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
  </dependency>
</dependencies>
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>${spring-cloud.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

pojo

api

Pom.xml

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>org.example</groupId>
        <artifactId>pojo</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zipkin</artifactId>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

UserOrderFeign

@FeignClient(value = "order-service",fallback = UserOrderFeignHystrix.class)
public interface UserOrderFeign {
    @GetMapping("getOrderByUserId")
    Order getOrderByUserId(@RequestParam int ID);

}

@Component
public class UserOrderFeignHystrix implements UserOrderFeign {

    @Override
    public Order getOrderByUserId(int ID) {
        return null;
    }

}

Order-center 提供者

Pom.xml

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>org.example</groupId>
        <artifactId>project-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zipkin</artifactId>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

@RestController
public class OrederController implements UserOrderFeign {

    @Override
    public Order getOrderByUserId(int ID) {
        Order egg = Order.builder().ID(101).name("炸蛋").price(1.5).build();
        return egg;
    }

}

application.yml

server:
  port: 8080
spring:
  application:
    name: order-service
    zipkin:
      base-url: http://localhost:9411
    sleuth:
      sampler:
        probability: 1 #取值0-1  ,1为100%采集
        rate: 10  #每秒间隔接受的trace量

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
  instance:
    hostname: localhost
    instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}

User-center

Pom.xml

<dependencies>
    <dependency>
        <groupId>org.example</groupId>
        <artifactId>project-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zipkin</artifactId>
    </dependency>
</dependencies>

@RestController
public class UserController {

    @Resource
    public UserOrderFeign userOrderFeign;

    @GetMapping("seek")
    public Order seekOrder(){
        Order orderByUserId = userOrderFeign.getOrderByUserId(101);
        return orderByUserId;
    }

}

application.yml

server:
  port: 8081
spring:
  application:
    name: user-service
    zipkin:
      base-url: http://localhost:9411
    sleuth:
      sampler:
        probability: 1 #取值0-1  ,1为100%采集
        rate: 10  #每秒间隔接受的trace量

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
  instance:
    hostname: localhost
    instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
feign:
  hystrix:
    enabled: true #开启熔断

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

QGS-CD

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值