欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

使用Spring Cloud Feign作为HTTP客户端调用远程HTTP服务的方法(推荐)

程序员文章站 2023-11-26 19:28:40
在spring cloud netflix栈中,各个微服务都是以http接口的形式暴露自身服务的,因此在调用远程服务时就必须使用http客户端。我们可以使用jdk原生的ur...

在spring cloud netflix栈中,各个微服务都是以http接口的形式暴露自身服务的,因此在调用远程服务时就必须使用http客户端。我们可以使用jdk原生的urlconnection、apache的http client、netty的异步http client, spring的resttemplate。但是,用起来最方便、最优雅的还是要属feign了。

feign简介

feign是一种声明式、模板化的http客户端。在spring cloud中使用feign, 我们可以做到使用http请求远程服务时能与调用本地方法一样的编码体验,开发者完全感知不到这是远程方法,更感知不到这是个http请求。比如:

@autowired
private advertgropremoteservice service; // 远程服务
public advertgroupvo foo(integer groupid) {
 return service.findbygroupid(groupid); // 通过http调用远程服务
}

开发者通过service.findbygroupid()就能完成发送http请求和解码http返回结果并封装成对象的过程。

feign的定义

为了让feign知道在调用方法时应该向哪个地址发请求以及请求需要带哪些参数,我们需要定义一个接口:

@feignclient(name = "ea") // [a]
public interface advertgroupremoteservice {
 @requestmapping(value = "/group/{groupid}", method = requestmethod.get) // [b]
 advertgroupvo findbygroupid(@pathvariable("groupid") integer adgroupid) // [c]
 @requestmapping(value = "/group/{groupid}", method = requestmethod.put)
 void update(@pathvariable("groupid") integer groupid, @requestparam("groupname") string groupname)

a: @feignclient用于通知feign组件对该接口进行代理(不需要编写接口实现),使用者可直接通过@autowired注入。

b: @requestmapping表示在调用该方法时需要向/group/{groupid}发送get请求。

c: @pathvariable与springmvc中对应注解含义相同。

spring cloud应用在启动时,feign会扫描标有@feignclient注解的接口,生成代理,并注册到spring容器中。生成代理时feign会为每个接口方法创建一个requettemplate对象,该对象封装了http请求需要的全部信息,请求参数名、请求方法等信息都是在这个过程中确定的,feign的模板化就体现在这里。

在本例中,我们将feign与eureka和ribbon组合使用,@feignclient(name = "ea")意为通知feign在调用该接口方法时要向eureka中查询名为ea的服务,从而得到服务url。

feign的encoder、decoder和errordecoder

feign将方法签名中方法参数对象序列化为请求参数放到http请求中的过程,是由编码器(encoder)完成的。同理,将http响应数据反序列化为java对象是由解码器(decoder)完成的。

默认情况下,feign会将标有@requestparam注解的参数转换成字符串添加到url中,将没有注解的参数通过jackson转换成json放到请求体中。注意,如果在@requetmapping中的method将请求方式指定为post,那么所有未标注解的参数将会被忽略,例如:

@requestmapping(value = "/group/{groupid}", method = requestmethod.get)
void update(@pathvariable("groupid") integer groupid, @requestparam("groupname") string groupname, dataobject obj);

此时因为声明的是get请求没有请求体,所以obj参数就会被忽略。

在spring cloud环境下,feign的encoder*只会用来编码没有添加注解的参数*。如果你自定义了encoder, 那么只有在编码obj参数时才会调用你的encoder。对于decoder, 默认会委托给springmvc中的mappingjackson2httpmessageconverter类进行解码。只有当状态码不在200 ~ 300之间时errordecoder才会被调用。errordecoder的作用是可以根据http响应信息返回一个异常,该异常可以在调用feign接口的地方被捕获到。我们目前就通过errordecoder来使feign接口抛出业务异常以供调用者处理。

feign的http client

feign在默认情况下使用的是jdk原生的urlconnection发送http请求,没有连接池,但是对每个地址会保持一个长连接,即利用http的persistence connection 。我们可以用apache的http client替换feign原始的http client, 从而获取连接池、超时时间等与性能息息相关的控制能力。spring cloud从brixtion.sr5版本开始支持这种替换,首先在项目中声明apache http client和feign-httpclient依赖:

<!-- 使用apache httpclient替换feign原生httpclient -->
 <dependency>
 <groupid>org.apache.httpcomponents</groupid>
 <artifactid>httpclient</artifactid>
 </dependency>
 <dependency>
 <groupid>com.netflix.feign</groupid>
 <artifactid>feign-httpclient</artifactid>
 <version>${feign-httpclient}</version>
 </dependency>

然后在application.properties中添加:

feign.httpclient.enabled=true

总结

通过feign, 我们能把http远程调用对开发者完全透明,得到与调用本地方法一致的编码体验。这一点与阿里dubbo中暴露远程服务的方式类似,区别在于dubbo是基于私有二进制协议,而feign本质上还是个http客户端。如果是在用spring cloud netflix搭建微服务,那么feign无疑是最佳选择。

以上所述是小编给大家介绍的使用spring cloud feign作为http客户端调用远程http服务的方法(推荐),希望对大家有所帮助