概述
Spring Cloud
Feign 概述
Feign 是一个声明web服务客户端,这便得编写web服务客户端更容易,使用Feign 创建一个接口并对它进行注解,它具有可插拔的注解支持包括Feign注解与JAX-RS注解,Feign还支持可插拔的编码器与解码器,支持拦截器,支持日志,支持重试,相较于HTTPClient多了一种概念,面向接口。所有的请求服务都存放在对应的FeignClient接口中。类似于一种模板调用。省去了大量冗余在配置文件写的的URL配置项,而且直接以接口形式来展示远端的请求,配合合理的日志打印,可以直观的发现服务调用的过程,及参数。便于排查。
原生的netflix的feign
- 先在pom文件中引入feign的依赖
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
<version>8.18.0</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-jackson</artifactId>
<version>8.18.0</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>8.18.0</version>
</dependency>
- feign-core是整个调用的核心
- feign-jackson是用于加密解密,还有feign-Gson
- feign-okhttp是一个处理网络请求的开源项目
okhttp相较于HttpClient
- 允许连接到同一个主机地址的所有请求,提高请求效率
- 共享Socket,减少对服务器的请求次数
- 通过连接池,减少了请求延迟
- 缓存响应数据来减少重复的网络请求
- 减少了对数据流量的消耗
- 自动处理GZip压缩
创建OkHttpClient,添加配置
@Bean
public okhttp3.OkHttpClient okHttpClient(){
okhttp3.OkHttpClient.Builder ClientBuilder = new okhttp3.OkHttpClient.Builder()
.readTimeout(30, TimeUnit.SECONDS) //读取超时
.connectTimeout(10, TimeUnit.SECONDS) //连接超时
.writeTimeout(60, TimeUnit.SECONDS) //写入超时
.connectionPool(new ConnectionPool(10 /*maxIdleConnections*/, 3, TimeUnit.MINUTES));
return ClientBuilder.build();
}
Feign构建自己的build
OkHttp 支持 SPDY (SPDY是Google开发的基于TCP的传输层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验),并有更好的控制http请求
@Bean
public XXX clientIdRemoteService() {
// Feign.builder();
log.info("初始化获取服务的Feign接口");
return Feign.builder()
.logger(new MyLogger())
.logLevel(MyLogger.Level.FULL)
.retryer(new MyRetryer(100L,1L,3))
// .encoder(new GsonEncoder())
// .decoder(new GsonDecoder())
.decode404()
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.client(new OkHttpClient(okHttpClient))
.target(XXX.class, server);
}
可以配置自定义的日志和重试策略
logLevel用来指定日志的级别
logLevel
- NONE:默认值,不进行日志记录
- BASIC:记录请求方法、URL、响应状态代码和执行时间
- HEADERS:除了 BASIC 记录的信息外,还包括请求头和响应头
- FULL:记录全部日志,包括请求头、请求体、请求与响应的元数据
server代表调用目标的主机
配置的XXX.calss在调用build()方法是调用ReflectiveFeign去创建一个Feign代理后的对象。
Builder.java
Builder内部类中的build方法
public Feign build() {
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404);
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder,
errorDecoder, synchronousMethodHandlerFactory);
return new ReflectiveFeign(handlersByName, invocationHandlerFactory);
}
上述代码中的编码,解码支持热拔插。Sax支持以sax方式解析XMl,JAXB也是对XMl的编码器解码器
Feign的注解
- @RequestLine(“GET /repos/{owner}/{repo}/contributors”)
RequestLine注解声明请求方法(POST,GET,PUT… )和请求地址,可以允许有查询参数 - @Headers 设置静态请求头可以设置在全局也可以给某一个方法单独使用,注解中也支持参数
@Headers(“Accept: application/json”), @Headers(“Content-Type: application/json”)
@Headers(“X-Ping: {token}”) - @Param(“owner”)
所有的参数(包括RequestLine中的还有Headers中的)均采用@Param来来接收。 - @QueryMap可以用来传输动态参数。
V find(@QueryMap Map<String, Object> queryMap); - 动态传输请求头信息使用@HeaderMap @HeaderMap 注解设置的请求头优先于其他方式设置的也就说会覆盖@Headers()中设置的。
void post(@HeaderMap Map<String, Object> headerMap);
@Body("<login “user_name”="{user_name}" “password”="{password}"/>")
void xml(@Param(“user_name”) String user, @Param(“password”) String password);
// 这里JSON格式需要的花括号需要转码。
@Body("%7B"search": “{search}”%7D")
void json(@Param(“user_name”) String user, @Param(“password”) String password); - @Body注解申明一个请求体模板,模板中可以带有参数,与方法中 @Param 注解申明的参数相匹配,使用@Body注解传输json对象是必须配合 @Headers(“Content-Type: application/json”)一起使用
此处要说一个插件JAX-RS
使用 JAX-RS 规范重写覆盖了默认的注解处理。
interface GitHub {
@GET @Path("/repos/{owner}/{repo}/contributors")
List<Contributor> contributors(@PathParam("owner") String owner, @PathParam("repo") String repo);
}
// contract 方法配置注解处理器,注解处理器定义了哪些注解和值是可以作用于接口的
GitHub github = Feign.builder()
.contract(new JAXRSContract())
.target(GitHub.class, "https://api.github.com");
@GET代表请求方式。@Path代表请求路径,@PathParam ,@QueryParam()代替了@Parm,@PathParam代表获取路径上的参数,@QueryParam(“fack”)获取请求参数上的参数,@Produces指定返回值类型等等,可以参见JAX-RS 规范
Ribbon集成
<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson -->
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-ribbon</artifactId>
<version>8.18.0</version>
</dependency>
RibbonClient 重写了 Feign 客户端的对URL的处理,其添加了 智能路由以及一些其他由Ribbon提供的弹性功能。
集成Ribbon需要你将ribbon的客户端名称当做url的host部分来传递
MyService api = Feign.builder().client(RibbonClient.create()).target(MyService.class, "https://RibbonClient");
Hystrix集成
<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson -->
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-hystrix</artifactId>
<version>8.18.0</version>
</dependency>
HystrixFeign 配置了 Hystrix 提供的熔断机制。
要在 Feign 中使用 Hystrix ,你需要添加Hystrix模块到你的环境变量,然后使用 HystrixFeign 来构造你的API:
MyService api = HystrixFeign.builder().target(MyService.class, "https://myAppProd");
Spring Cloud Feign集成
Spring Cloud 增加了对 Spring MVC的注解,Spring Web 默认使用了HttpMessageConverters, Spring Cloud 集成 Ribbon 和 Eureka 提供的负载均衡的HTTP客户端 Feign
SpringCloudFeign呢同样同样也是定义一个接口即可
@FeignClient(url="Server",value="helloServiceClient")
public interface HelloService{
@RequestMapping("getUser")
User getUserById(@RequestParam(value="id")Integer id);
}
如果只是单独使用feign功能不配合Eureka的情况下,需要在注解中配置url=“Server” 这个参数是目标主机的server,value是这个接口的定义的bean的name。
Feign的高级用法可以使用继承,这个一般配合Eureka使用,定义一个Feign的service接口,并且写一个实现类直接把该类标记为@RestController,在feign调用的的Server端则直接引入依赖继承该接口即可,feign的Client端直接调用,继承的优点就不再累述了,就直接说一下项目中使用的时候出现的问题吧,在开发中多端调用的情况很多,这就需要开项目开发前期的时候就做好几口的设计,应为当基类一旦被修改,那么各个项目组的代价是很大的。。。
当Feign出现的时候。Ribbon是伴生出现的。当@FeignClient(url=“Server”,value=“helloServiceClient”)
出现的时候,会创建一个feign客户端也会创建一个Ribbon客户端。Feign的默认是由超时重试功能的,但是这个超时会有俩个影响,其一,超时回应其Ribbon的retry机制,还有就是会引起熔断。故而在项目开发过程中,切记要把Hystrix的超时时间设置大于Ribbon的超时时间,不然你就会看到服务被降级,而不是重试了。你开发想测试Ribbon的超时重试可以吧Hystrix熔断机制关闭,
feign.hystrix.enabled=false
,至于熔断机制的我会在下一篇Hystrix原理解析中详细阐述,
在这里你先可以记住,可以写一个实现Feign接口的实现类定义启动熔断注解就可以实现在方法调用不通时候。返回降级的数据,从而不会导致整个项目进入不可用状态。
使用方式
@FeignClient(url=“Server”,value=“helloServiceClient”,fallback=“CallbackHelloServer.class”)
此外feign在SpringCloud中的集成依旧包括上述原生netflix的配置日志,加密解密,还有一点项目中优化比较常用的是对feign调用的数据启用gzip压缩
feign.cpmression.request.enabled=true;
feign.cpmression.response.enabled=true;
写于教师节。祝愿我的老师们,安康。平安。
最后
以上就是贤惠皮皮虾为你收集整理的Feign分析的全部内容,希望文章能够帮你解决Feign分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复