使用okhttp替换Feign默认Client的操作
一关键pom
org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-openfeign io.github.openfeign feign-okhttp
二核心配置
server: port:8011 spring: application: name:ch4-3-okhttp feign: httpclient: enabled:false okhttp: enabled:true
三其他代码位置
https://github.com/cakin24/spring-cloud-code/tree/master/ch4-3/ch4-3-okhttp
四运行测试
补充:Feign-独立使用-替代HttpClient
学习项目中,短连接Web服务器和长连接IM服务器之间,是相互配合的。在分布式集群的环境下,用户首先通过短连接登录Web服务器。Web服务器在完成用户的账号/密码验证,返回uid和token时,还需要通过一定策略,获取目标IM服务器的IP地址和端口号列表,返回给客户端。客户端开始连接IM服务器,连接成功后,发送鉴权请求,鉴权成功则授权的长连接正式建立。
短连接的调用,使用Feign技术。下面是详解。
看完之后,Feign独立使用,完全可以替换掉目前的Http客户端调用方法。
1.1.Feign短连接Restful调用
一般来说,短连接的服务接口,都是基于应用层Http协议的Httpapi或者RESTfulapi实现,通过JSON文本格式返回数据。如何在Java服务端调用其他节点的Httpapi或者RESTfulapi呢?
至少有以下几种方式:
(1)JDK原生的URLConnection
(2)Apache的HttpClient/HttpComponents
(3)Netty的异步HTTPClient
(4)Spring的RestTemplate
目前用的最多的,基本上是第二种,这也是在单体服务时代,最为成熟和稳定的方式,也是效率较高的短连接方式。
插入一个解释:什么是RESTfulapi。REST的全称是RepresentationalStateTransfer,它是一种API接口的风格、也而不是标准,只是提供了一组调用的原则和约束条件。也就是说,在短连接服务的领域,它算是一种特殊格式的HTTPapi。
回到前面的话题,如果同一个Httpapi/RESTfulapi接口,倘若不止一个短连接服务器提供,而是有多个节点提供服务,那么,简单的使用HttpClient调用,就无能为力了。
HttpClient/HttpComponents调用不能根据接口的负载、或者其他的条件,去判断哪一个接口应该调用,哪一个接口不应该调用。解决这个问题的方式是啥呢?
可以使用Feign来调用多个服务器的同一个接口。Feign不仅仅可以进行同接口多服务器的负载均衡,一旦使用了Feign作为httpapi的客户端,调用远程的http接口就会变得像调用本地方法一样简单。
Feign是何方神圣?它是Netflix开发的一个声明式、模板化的HTTP客户端,Feign的目标是帮助Java工程师更快捷、优雅地调用HTTPAPI//RESTfulapi。另外,Feign被无缝集成到了SpringCloud微服务框架,使用Feign后,可以非常方便项目SpringCloud微服务技术。
如果项目使用了SpringCloud技术,那就就可以更加方便的声明式使用Feign。如果没有使用SpringCloud,使用Feign也非常之简单。NetflixFeign目前改名为OpenFeign,最新版本是2018.5发布的9.7.0。OpenFeign在Java应用中,负责处理与远程Web服务的请求响应,最大限度降低编码复杂性。可以说是Java应用中调用Web服务的客户端的利器。
下面就看看在单独使用Feign的场景下,是怎么调用远程的http服务。
引入Feign依赖的jar包到pom.xml:
io.github.openfeign feign-core 9.7.0 io.github.openfeign feign-gson 9.7.0
接下来,就可以开始使用Feign来调用远程的HttpAPI了。
1.1.1.短连接API的接口准备
前面讲到,高并发的IM系统中,用户的登录与认证、好友的更新与获取等等一些低频的请求,这些都使用短连接来实现。
作为演示,这里仅仅列举两个短连接的API接口:
(1)http://localhost:8080/user/{userid}
这个接口的功能,是用户获取用户信息,是一个典型的RESTful类型的接口。{userid}是一个占位符,调用的时候,需要替换成用户id。比如说如果用户id为1,调用的链接为:http://localhost:8080/user/1。
(2)http://localhost:8080/login/{username}/{password}
这个接口的功能,用户登录的认证。占位符{username}是表示用户名称,占位符{password}表示用户密码。比如说如果用户名称为zhangsan,密码为123调用的链接为:http://localhost:8080/login/zhangsan/123。
上面的接口很简单,仅仅是为了演示,不能用于生产场景。这些API可以使用SpringMVC等常见的WEB技术来实现。
1.1.2.申明远程接口的本地代理
如何通过Feign技术,来调用上面的这些HttpAPI呢?
第一步,需要创建一个本地的API的代理接口。具体如下:
packagecom.crazymakercircle.imServer.feignClient; importfeign.Param; importfeign.RequestLine; publicinterfaceUserAction { @RequestLine("GET/login/{username}/{password}") publicStringloginAction( @Param("username")Stringusername, @Param("password")Stringpassword); @RequestLine("GET/user/{userid}") publicStringgetById( @Param("userid")Integeruserid); }
在代理接口中,为每一个远程HttpAPI定义一个方法。
如何将方法对应到远程接口呢?
在方法的前面,加上一个@RequestLine注解,注明远程HttpAPI的请求地址。这个地址不需要从域名和端口开始,只需要从URI的根目录“/”开始即可。
比如,如果远程HttpAPI的URL为:http://localhost:8080/user/{userid},@RequestLine声明的值,只需要配成/user/{userid}即可。
如何给接口传递参数值呢?
在方法的参数前面,加上一个@Param注解即可。@Param内容为HTTP链接中参数占位符的名称。绑定好之后,实际这个Java接口中的参数值,会替换到@Param注解中的占位符。
比如:由于getById的唯一参数userid的@Param注解中,用到的占位符是userid。那么,通过调用userAction.getById(100),那么userid的值100,就会用来替换掉请求链接http://localhost:8080/user/{userid}中占位符userid,最终得到的请求链接为:http://localhost:8080/user/100。
1.1.3.远程API的本地调用
在完成远程API的本地代理接口的定以后,接下来的工作就是调用本地代理,这个工作也是非常的简单。
还是以疯狂创客圈的实战项目,获取用户信息、和用户登录两个API的代理接口的调用为例。
实战的代码如下:
importcom.crazymakercircle.imServer.feignClient.UserAction; importfeign.Feign; importfeign.Request; importfeign.Retryer; importfeign.codec.StringDecoder; importorg.junit.Test; /** *Createdby尼恩at疯狂创客圈 */ //@ContextConfiguration( //locations={"classpath:application.properties"}) //@RunWith(SpringJUnit4ClassRunner.class) //@Configuration //自动加载配置信息 //@EnableAutoConfiguration publicclassLoginActionTest { /*//服务器ip地址 @Value("${server.web.user.url}") privateStringuserBase;*/ @Test publicvoidtestLogin() { UserActionaction=Feign.builder() //.decoder(newGsonDecoder()) .decoder(newStringDecoder()) .options(newRequest.Options(1000,3500)) .retryer(newRetryer.Default(5000,5000,3)) .target( UserAction.class, //userBase "http://localhost:8080/" ); Strings=action.loginAction( "zhangsan", "zhangsan" ); System.out.println("s="+s); } @Test publicvoidtestGetById() { UserActionaction=Feign.builder() //.decoder(newGsonDecoder()) .decoder(newStringDecoder()) .target( UserAction.class, "http://localhost:8080/" ); Strings=action.getById(2); System.out.println("s="+s); } }
主要的也是最为核心的就一步,构建一个远程代理接口的本地实例。使用Feign.builder()构造器模式方法,带上一票配置方法的链式调用。主要的链式调用的配置方法介绍如下:
(1)target配置方法
为构造器配置本地的代理接口,和远程的根目录。代理接口类的每一个接口方法前@RequestLine声明的值,最终都会加上这个根目录。这个是最为重要的一个配置方法。代理接口类很重要,最终Feign.builder()构造器返回的本地代理实例类型,就这个接口。
(2)options配置方法
options方法指定连接超时时长及响应超时时长。
(3)retryer配置方法
retryer方法主要是指定重试策略。
(4)decoder配置方法
decoder方法指定对象解码方式,这里用的是基于String字符串的解码方式。如果需要使用Jackson的解码方式,需要在pom.xml中添加Jackson的依赖。
主要的配置方法,就介绍这些,具体使用和其他的方法,请参见官网。
通过Feign.builder()构造完成代理实例后,调用远程API,就变成了调用Java函数一样的简单。
建议,如果是独立调用Http服务,尽量使用Feign。
一是简单,
二是如果采用httpclient或其他相对较重的框架,对初学者来说编码量与学习曲线都会是一个挑战。
三是,既可以独立使用Feign,又可以方便后续的和SpringCould微服务框架继承。
总之,何乐而不为呢?
以上为个人经验,希望能给大家一个参考,也希望大家多多支持毛票票。如有错误或未考虑完全的地方,望不吝赐教。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。