1. Feign调用服务接口

Java工程接口调用方式

1. Httpclient

HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持Http协议的客户端编程工具包,并且它支持HTTP协议最新版本和建议。HttpClient相比传统JDK自带的URLConnection,提升了易用性和灵活性,使客户端发送HTTP请求变得容易,提高了开发的效率。

2. Okhttp

一个处理网络请求的开源项目,是安卓端最火的轻量级框架,由Square公司贡献,用于替代 HttpUrlConnection和Apache HttpClient。OkHttp拥有简洁的API、高效的性能,并支持多种协议(HTTP/2 和 SPDY)。

3. HttpURLConnection

HttpURLConnection是Java的标准类,它继承自URLConnection,可用于向指定网站发送GET请求、POST请求。HttpURLConnection使用比较复杂,不像HttpClient那样容易使用。

4. RestTemplate

RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程HTTP服务的方法,能够大大提高客户端的编写效率。

5. Feign

Feign是一个声明式的REST客户端,它能让REST调用更加简单。Feign供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息。

SpringCloud集成Feign

spring-cloud-starter-openfeign的依赖是SpringBoot2.0以后专用的,如果您使用的SpringBoot版本低于2.0请使用spring-cloud-starter-feign。

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-openfeign</artifactId>
  4. </dependency>

在启动类上加注解“@EnableFeignClients”。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class,args);
    }

}

使用Feign调用接口

定义一个Feign的客户端。

import com.FeignConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(name = "service-product")
public interface ProductServiceClient {

    @GetMapping(value = "/ribbon/hello1")
    String testRibbom1(@RequestParam("a")String a);

}

接下来采用Feign来调用“/service-product/ribbon/hello1”接口。

import com.smart.feginclient.ProductServiceClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FeginController {

    @Autowired
    private ProductServiceClient productServiceClient;

    @GetMapping("/fegin/product/test")
    public String feignTest(){
        return productServiceClient.testRibbom1("sdfsdfsdf");
    }

}

2. Feign自定义配置及使用

import com.smart.interceptor.FeginBasicAuthRequestInterceptor;
import feign.Contract;
import feign.Logger;
import feign.Request;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignConfiguration
{
    /*@Bean
    public Contract feignContract() {
        return new feign.Contract.Default();
    }*/
    /**
     * 日志级别
     * 日志等级有4种,分别是:
     * NONE:不输出日志。
     * BASIC:只输出请求方法的 URL 和响应的状态码以及接口执行的时间。
     * HEADERS:将 BASIC 信息和请求头信息输出。
     * FULL:输出完整的请求信息。
     * 在配置文件中执行 Client 的日志级别才能正常输出日志,格式是“logging.level.client 类地址=级别”。
     * logging.level.com.smart.feginclient.ProductServiceClient=debug
     */
    @Bean
    Logger.Level feginLoggerLevel(){
            return Logger.Level.FULL;
    }
    /**
    * Basic 认证配置
    * 通常我们调用的接口都是有权限控制的,很多时候可能认证的值是通过参数去传递的,还有就是通过请求头去传递认证信息,比如 Basic 认证方式。在 Feign 中我们可以直接配置 Basic 认证,代码如下所示
    */
    @Bean
    BasicAuthRequestInterceptor basicAuthRequestInterceptor(){
            return new BasicAuthRequestInterceptor("dxh", "123456");
    }
    /**
    * 自定义拦截器,当fegin去请求接口之前,每次请求都会进入拦截器中
    */
    @Bean
    FeginBasicAuthRequestInterceptor feginBasicAuthRequestInterceptor(){
            return new FeginBasicAuthRequestInterceptor();
    }
    /**
    * 超时时间配置
    * Options 的第一个参数是连接超时时间(ms),默认值是 10×1000;第二个是取超时时间(ms),默认值是 60×1000。
    *@Bean
    *public Request.Options options(){
    *    return new Request.Options(5000,10000);
    *}
    */
}

fegin拦截器。

import feign.RequestInterceptor;
import feign.RequestTemplate;

public class FeginBasicAuthRequestInterceptor implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate requestTemplate) {
        System.out.println("Fegin请求拦截器");
    }

}

配置类建好后,我们需要在Feign Client中的注解“@FeignClient”中指定使用的配置类。

import com.FeignConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(name = "service-product",configuration = FeignConfiguration.class)
public interface ProductServiceClient {

    @GetMapping(value = "/ribbon/hello1")
    String testRibbom1(@RequestParam("a")String a);

}

自定义Feign配置

# 链接超时时间
##feign.client.config.feignName.connectTimeout=5000
# 读取超时时间
##feign.client.config.feignName.readTimeout=5000
# 重试
#feign.client.config.feignName.retryer=com.example.SimpleRetryer
# 日志等级
feign.client.config.feignName.loggerLevel=full
# 拦截器
feign.client.config.feignName.requestInterceptors[0]=com.example.FooRequestInterceptor
feign.client.config.feignName.requestInterceptors[1]=com.example.BarRequestInterceptor
# 编码器
feign.client.config.feignName.encoder=com.example.SimpleEncoder
# 解码器
feign.client.config.feignName.decoder=com.example.SimpleDecoder
# 开启压缩可以有效节约网络资源,提升接口性能,我们可以配置 GZIP 来压缩数据:
feign.compression.request.enabled=true
feign.compression.response.enabled=true
# 配置压缩的类型、最小压缩值的标准
feign.compression.request.mime-types=text/xml,application/xml,application/json
feign.compression.request.min-request-size=2048

重试机制

由于SpringCloud Feign的客户端负载均衡时通过SpringCloud Ribbon实现的,所以我们可以直接通过配置Ribbon客户端的方式来自定义各个服务客户端的参数。

ribbon.ReadTimeout=3000
ribbon.ConnectTimeout=3000
# 同一台实例最大重试次数,不包括首次调用
ribbon.MaxAutoRetries=1
# 重试负载均衡其他的实例最大重试次数,不包括首次调用
ribbon.MaxAutoRetriesNextServer=1
# 是否所有操作都重试
ribbon.OkToRetryOnAllOperations=false

根据上面的参数计算重试的次数:“MaxAutoRetries+MaxAutoRetriesNextServer+(MaxAutoRetries *MaxAutoRetriesNextServer) ”,即重试3次 则一共产生4次调用。
如若使用了hystrix熔断机制,如果在重试期间,时间超过了hystrix的超时时间,便会立即执行熔断,fallback。所以要根据上面配置的参数计算hystrix的超时时间,使得在重试期间不能达到hystrix的超时时间,不然重试机制就会没有意义 hystrix超时时间的计算: “**(1 + MaxAutoRetries + MaxAutoRetriesNextServer) ReadTimeout**”,即按照以上的配置 hystrix的超时时间应该配置为 (1+1+1)3=9秒。
注意:如果不配置Ribbon的重试次数,默认会重试一次默认情况下,GET方式请求无论是连接异常还是读取异常,都会进行重试非GET方式请求,只有连接异常时才会进行重试__ 。

继承特性

Feign的继承特性可以让服务的接口定义单独抽出来,作为公共的依赖,以方便使用。创建一个Maven项目 feign-inherit-api,用于存放API接口的定义,增加Feign的依赖,代码如下所示。

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

定义接口,指定服务名称,代码如下所示。

@FeignClient("feign-inherit-provide")
public interface UserRemoteClient {
    @GetMapping("/user/name")
    String getName();
}

创建一个服务提供者feign-inherit-provide,引入feign-inherit-api,代码如下所示:

<dependency>
    <groupId>net.biancheng</groupId>
    <artifactId>feign-inherit-api</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

实现 UserRemoteClient 接口,代码如下所示:

@RestController
public class DemoController implements UserRemoteClient {
    @Override
    public String getName() {
        return "zhangsan";
    }
}

创建一个服务消费者feign-inherit-consume,同样需要引入feign-inherit-api用于调用feign-inherit-provide 提供的“/user/name”接口,代码如下所示:

@RestController
public class DemoController {
    @Autowired
    private UserRemoteClient userRemoteClient;
    @GetMapping("/call")
    public String callHello() {
        String result = userRemoteClient.getName();
        System.out.println("getName调用结果:" + result);
    }
}

通过将接口的定义单独抽出来,服务提供方去实现接口,服务消费方直接就可以引入定义好的接口进行调用,非常方便。

参考

CSDN:SpringCloud之Feign、Ribbon设置超时时间和重试机制的总结
https://blog.csdn.net/east123321/article/details/82385816
C语言中文网:Spring Cloud Feign的自定义配置及使用
http://c.biancheng.net/view/5362.html