OpenFeign要被HttpExchange替代了吗?
前言
Http是最常见的请求协议,每种编程语言都可发送Http请求。Java作为经典编程语言之一,发送Http请求的客户端更是不少,自己的内置的就有java.net.HttpURLConnection以及Java 11以后的java.net.http.HttpClient。在Java 11之前,HttpURLConnection很难用,因此市场上百花齐放出现了不少优秀的开源作品,典型代表为:Apache HttpClient(现最新为Http Component 5.x)OkHttp(现最新为OkHttp 4.x)
作为老牌的Apache HttpClient凭借着各种优秀特征,似乎已成为了事实的标准;后起之秀OkHttp不带历史包袱的轻装上路,有着低网络延迟、更优秀的连接池性能,亦是一股不可轻视的力量。
Spring不到万不得已之时,一般不会自己重复造轮子。在Http客户端这块一样借力打力,提供Http统一调用方式RestTemplate,屏蔽了细节,规范了开发者的使用,简化了开发门槛。
PS:RestTemplate的底层实现依旧是Apache HttpClient、OkHttp、HttpURLConnection之一
以上,都还是编程式Http客户端。随着Spring Boot的普及,Spring Cloud的出现,声明式编码变得越来越主流,因为声明式/面向元数据编码效率远高于编程式编码效率。因此,Feign出现了,迅速成为了主流。
今年,随着划时代版本Spring Framework 6、Spring Boot 3、Spring Cloud 2022.0.0的发布,Spring团队自建了一套声明式Http客户端:@HttpExchange,目标直指OpenFeign。正文
全新的声明式Http客户端由Spring Framework 6提供定义,Spring Boot 3提供实现,Spring Cloud 2022负责发扬光大。今天我们就来体验一把介绍一个免费的、在线的Rest Http服务
由于我们需要一个提供Http Server来提供接口服务,为此先给你介绍一个免费的、24h在线的Rest Http服务,省去我们自己搭建的麻烦。
地址:jsonplaceholder.typicode.com
每月提供近20亿的请求,关键还是免费的、可公开访问的,好用得不要不要。
发一个简单的Http请求,就能获取到数据。URL遵循Rest规范:
不挑Http或者Https,比如使用浏览器访问这个URL得到的结果也是一样的:
它提供多个Resources资源(以及多种Routes)供以访问,对这些资源进行增删改查的操作,你想要的绝大部分都能满足你。当然,若你需要mock data是符合自己的数据结构、业务逻辑的,可基于此项目做简单的修改即可,良心项目啊。具体详情自行去官方体验:https://jsonplaceholder.typicode.com。全新声明式Http客户端@HttpExchange
环境声明:Spring Boot 3.0.x
本文选用"albums"资源进行测试:https://jsonplaceholder.typicode.com/albums的请求结果结构如下:
Feign代码示例
略!Feign的使用,相信大家再熟悉不过了,笔者这里就不费周章。@HttpExchange代码示例
按照albums的返回数据结构,写Java Bean:
复制/*** 在此处添加备注信息** @author YourBatman* @since 0.0.1*/@Builder@GetterpublicclassAlbumsReq { @NotNull@PositiveprivateLonguserId; @NotBlankprivateStringtitle; } /*** 在此处添加备注信息** @author YourBatman* @since 0.0.1*/@Setter@ToStringpublicclassAlbumsResp { privateLongid; privateLonguserId; privateStringtitle; }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.
顺带科普一个编码规范:请求体Req中get方法是必须的,set方法可选;响应体Resp中set方法是必须的,get方法可选;二者都需遵循Java Bean规范! 粗暴的做法是不管需求如何,get/set一把梭,可行,但作为程序员的你应该知道原由,理解要义。
导入webflux包 此声明式客户端又Spring Framework 6提供,但由于其并未提供实现。Spring Boot 3为此提供了基于Reactive的Web实现,因此需要导入webflux包:
复制org.springframework.bootspring-boot-starter-webflux1.2.3.4.
编写Http客户端申明式接口。
复制/*** 在此处添加备注信息** @author YourBatman* @since 0.0.1*/@HttpExchange("/albums") publicinterfaceAlbumsClient { @GetExchangeListgetAll(); @GetExchange("/{id}") AlbumsRespgetById(@PathVariableLongid); @PostExchangeAlbumsRespadd(@RequestBody@ValidAlbumsReqreq); }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.
书写测试用例代码。
复制@SpringBootTestclassApplicationTests { @AutowiredprivateAlbumsClientalbumsClient; @TestvoidcontextLoads(){ System.out.println("getAll size:"+albumsClient.getAll().size()); System.out.println("getById 1:"+albumsClient.getById(1L)); // 创建一个ObjectaddedResp=albumsClient.add(AlbumsReq.builder().userId(1L).title("diy add...").build()); System.out.println("创建的allAlbums对象为:"+addedResp+",现在总数为:"+albumsClient.getAll().size()); } }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.
运行测试代码,控制台输出:
复制getAllsize:100getById1:AlbumsResp(id=1, userId=1, title=quidemmolestiaeenim) 创建的allAlbums对象为:AlbumsResp(id=101, userId=1, title=diyadd...),现在总数为:1001.2.3.
完美!
小细节:创建的时候并未制定id,发现id是自增的(id=101)。但这并不会保存在typicode.com的远端服务器了,不会引起总条数的变化。@HttpExchange声明式客户端简析
@HttpExchange是Spring Framework 6新提供的声明式Http客户端,客户端的要素由注解的属性 + 方法签名来定义。先来看看这个注解:
复制/*** Since: 6.0*/@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented@Mapping@Reflective(HttpExchangeReflectiveProcessor.class) public@interfaceHttpExchange { @AliasFor("url") Stringvalue() default""; @AliasFor("value") Stringurl() default""; Stringmethod() default""; StringcontentType() default""; String[] accept() default {}; }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.
和@RequestMapping参照对比:
复制@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented@Mapping@Reflective(ControllerMappingReflectiveProcessor.class) public@interfaceRequestMapping { Stringname() default""; @AliasFor("path") String[] value() default {}; @AliasFor("value") String[] path() default {}; RequestMethod[] method() default {}; String[] params() default {}; String[] headers() default {}; String[] consumes() default {}; String[] produces() default {}; }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.
不说一毛一样,也是基本一样。@HttpExchange注解可以标注在类上和方法上,最终的URL组合起来生效。大家都是使用过Feign、使用过Spring MVC的,这就不用过多介绍了。
和@RequestMapping一样,@HttpExchange也有其派生注解:@GetExchange:GET请求。类似于于@GetMapping@PostExchange:Post请求。类似于于@PostMapping@PutExchange:Put请求。类似于于@PutMapping@DeleteExchange:Delete请求。类似于于@DeleteMapping@PatchExchange:Patch请求。类似于于@PatchMapping@HttpExchange声明式客户端前景展望
通过interface这种声明式使用起来比RestTemplate,或者WebClient要简单很多,大大简化了开发步骤,对开发者更加友好。
最新发布的Spirng Cloud 2022.0.0里描述得很明白:停止对OpenFeign的特征支持。言外之意:OpenFeign即将被Spring Cloud"淘汰",接棒的那必然是@HttpExchange喽。所以在可预见的将来,前景一片大好。
但是,笔者认为它还不够成熟,主要有两点:还不能支持Spring-Web的注解(@RequestMapping体系),若能支持个人觉得会更为方便。目前还只有WebClient一套实现(由Spring Boot提供实现),而它属于Reactive Web体系,也就是必须引入webFlux相关技术,而webFlux在做业务开发时优势不明显,并非主流。因为若WebClient能从Reactive Web里剥离出来,笔者觉得就好很多了。总结
谁能想到,OpenFeign竟然都快被淘汰了,Spring的大船滚滚向前,引领着整个潮流,逐渐暴露出了野心,或者说感受到了危机。
先抄袭,再超越,Spring做到了。隐藏在全新的声明式客户端背后,其实还有Spring Framework 6背后对Web Mapping体系的重构,细心的你或许已有所发现。这些话题、新发现,留予笔者和你后续接着聊。
原文链接:https://www.51cto.com/article/743079.html