本文已被https://yourbatman.cn收录;女娲Knife-Initializr工程可公开访问啦;程序员专用网盘https://wangpan.yourbatman.cn;技术专栏源代码大本营:https://github.com/yourbatman/tech-column-learning;公号后台回复“专栏列表”获取全部小而美的原创技术专栏
你好,我是YourBatman:一个俗人,贪财好色。
Title | Link |
---|---|
所属专栏 | [YourBatman]-Spring技术栈 |
源代码 | https://github.com/yourbatman/FXP-java-ee |
程序员专用网盘公益上线啦,注册送1G超小容量,帮你实践做减法 | https://wangpan.yourbatman.cn |
Java开发软件包(Mac) | https://wangpan.yourbatman.cn/s/rEH0 提取码:javakit |
女娲工程 | http://152.136.106.14:8761 |
版本约定 | [Mac OS 13.1],[IDEA 2022.3.1],[Spring Boot 3.0.x] |
????前言
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
@Getter
public class AlbumsReq {
@NotNull
@Positive
private Long userId;
@NotBlank
private String title;
}
/**
* 在此处添加备注信息
*
* @author YourBatman
* @since 0.0.1
*/
@Setter
@ToString
public class AlbumsResp {
private Long id;
private Long userId;
private String title;
}
顺带科普一个编码规范:请求体Req中get方法是必须的,set方法可选;响应体Resp中set方法是必须的,get方法可选;二者都需遵循Java Bean规范! 粗暴的做法是不管需求如何,get/set一把梭,可行,但作为程序员的你应该知道原由,理解要义。
????????♀️导入webflux包
此声明式客户端又Spring Framework 6提供,但由于其并未提供实现。Spring Boot 3为此提供了基于Reactive的Web实现,因此需要导入webflux包:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
????????♀️编写Http客户端申明式接口
/**
* 在此处添加备注信息
*
* @author YourBatman
* @since 0.0.1
*/
@HttpExchange("/albums")
public interface AlbumsClient {
@GetExchange
List<AlbumsResp> getAll();
@GetExchange("/{id}")
AlbumsResp getById(@PathVariable Long id);
@PostExchange
AlbumsResp add(@RequestBody @Valid AlbumsReq req);
}
????????♀️Client配置类
/**
* 在此处添加备注信息
*
* @author YourBatman
* @since 0.0.1
*/
@Configuration(proxyBeanMethods = false)
public class WebClientConfiguration {
@Bean
public AlbumsClient albumsClient(WebClient.Builder webClientBuilder) {
WebClient webClient = webClientBuilder.baseUrl("https://jsonplaceholder.typicode.com").build();
return HttpServiceProxyFactory.builder().clientAdapter(WebClientAdapter.forClient(webClient)) //
.build().createClient(AlbumsClient.class);
}
}
????????♀️书写测试用例代码
@SpringBootTest
class ApplicationTests {
@Autowired
private AlbumsClient albumsClient;
@Test
void contextLoads() {
System.out.println("getAll size:" + albumsClient.getAll().size());
System.out.println("getById 1:" + albumsClient.getById(1L));
// 创建一个
Object addedResp = albumsClient.add(AlbumsReq.builder().userId(1L).title("diy add...").build());
System.out.println("创建的allAlbums对象为:" + addedResp + ",现在总数为:" + albumsClient.getAll().size());
}
}
????????♀️运行测试代码,控制台输出:
getAll size:100
getById 1:AlbumsResp(id=1, userId=1, title=quidem molestiae enim)
创建的allAlbums对象为:AlbumsResp(id=101, userId=1, title=diy add...),现在总数为:100
完美!
小细节:创建的时候并未制定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 @interface HttpExchange {
@AliasFor("url")
String value() default "";
@AliasFor("value")
String url() default "";
String method() default "";
String contentType() default "";
String[] accept() default {};
}
和@RequestMapping
参照对比:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
@Reflective(ControllerMappingReflectiveProcessor.class)
public @interface RequestMapping {
String name() 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 {};
}
不说一毛一样,也是基本一样。@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
里剥离出来,笔者觉得就好很多了
- 因为若WebClient能从
????总结
谁能想到,OpenFeign竟然都快被淘汰了,Spring的大船滚滚向前,引领着整个潮流,逐渐暴露出了野心,或者说感受到了危机。
先抄袭,再超越,Spring做到了。隐藏在全新的声明式客户端背后,其实还有Spring Framework 6背后对Web Mapping体系的重构,细心的你或许已有所发现。这些话题、新发现,留予笔者和你后续接着聊。
推荐阅读
- IntelliJ IDEA 2022.3正式发布,配置云同步&支持Redis好用到炸
- Spring Framework 6正式发布,携JDK 17&Jakarta EE开启新篇章
- IntelliJ IDEA 2022.2正式发布,支持Spring Boot 3和Spring 6
- JVM除了HotSpot,你还知道哪些?
- YourBatman用趣味代码雨祝你:端午安康
- 逐渐碎片化的Java生态圈:Oracle JDK、OpenJDK、阿里Dragonwell、华为毕昇
我是YourBatman:前25年不会写Hallo World、早已毕业的大龄程序员。高中时期《梦幻西游》骨灰玩家,网瘾失足、清考、延期毕业、房产中介、保险销售、送外卖…是我不可抹灭的黑标签
- ????2013.07 清考、毕业答辩3次未通过、延期毕业
- ????2013.08-2014.07 宁夏中介公司卖二手房1年,毕业后第1份工作
- ️️????2014.07-2015.05 荆州/武汉,泰康人寿卖保险3月、饿了么送外卖2月,还有炸鸡排、直销等第2345份工作
- ????2015.08 开始从事Java开发,闯过外包,呆过大厂!擅长抽象思维,任基础架构团队负责人
- ????2021.08 因“双减政策”失业!历经9面,终获美团外卖L8的offer
- ????????♀️Java架构师、Spring开源贡献者、CSDN博客之星年度Top 10、领域建模专家、写作大赛1/2届评委
- ????高质量代码、规范践行者;DDD领域驱动深度实践;即将出版书籍
《Spring奇淫巧技》
序号 | 专栏名称 | 简介 |
---|---|---|
01 | [YourBatman]-程序人生 | 程序人生,人生程序 |
02 | [YourBatman]-资讯/新特性 | IDEA、JDK、Spring技术栈…新特性 |
03 | [YourBatman]-IntelliJ IDEA | 熟练使用IDEA就相当拥有物理外挂,助你高效编码 |
04 | [YourBatman]-Bean Validation | 熟练掌握数据校验,减少90%的垃圾代码 |
05 | [YourBatman]-日期时间 | 帮你解决JDK Date、JSR 310日期/其实 的一切问题 |
06 | [YourBatman]-Spring类型转换 | Spring类型转换-框架设计的基石 |
07 | [YourBatman]-Spring static | static关键字在Spring里的应用 |
08 | [YourBatman]-Cors跨域 | 关于跨域请求问题,本专栏足矣 |
09 | [YourBatman]-Jackson | Almost Maybe是最好的Jackson专栏 |
10 | [YourBatman]-Spring配置类 | 专讲@Configuration配置类,你懂的 |
11 | [YourBatman]-Spring技术栈 | 暂无所属小分类的,Spring技术栈大分类 |
12 | [YourBatman]-JDK | 暂无所属小分类的,JDK技术栈大分类 |
13 | [YourBatman]-Servlet | Servlet规范、Web相关内容专题 |
14 | [YourBatman]-Java EE | 从Java EE到Jakarta EE,30年弹指一挥间 |
15 | [YourBatman]-工具/提效 | 开发工具、软件工具,目标是提效 |
16 | [YourBatman]-Spring技术栈新特性 | Spring Framework、Spring Boot、Spring Cloud、Spring其它技术 |
17 | [YourBatman]-基本功 | 每个Javaer,都需要有扎实的基本功 |
… | … | … |
99 | 源代码库 | 大多数专栏均配有源代码,都在这里 |