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。
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></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
