在Spring6之前,我们做http服务的请求主要是通过jdk中的URLConnection类,或者第三方http客户端调用库比如HttpClient和OkHttp,或者Spring6之前提供的RestTemplate工具。至于SpringCloud或者其他微服务框架中使用到的调用方式比如Ribbon、Feign之类的,不在本文讨论范围,因为那涉及到微服务概念中负载均衡,熔断等其他方面的内容,由于认知比较肤浅,暂不做讨论,只是为了说明一个http服务接口的客户端简单调用,下面将本人使用Spring6自带的注解完成http客户端请求过程描述如下。
首先客户端程序在使用Spring6框架的基础上,要引入spring-boot-starter-webflux,才能使用@HttpExchange,@GetExchange和@PostExchange这些注解,因为这些注解都是在该响应式包中的。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>
引入上述依赖以后,需要加入一个配置类,该配置类主要配置WebClient和需要使用该WebClient做调用的业务服务类。
publicclassWebConfig { WebClientwebClient() { returnWebClient.builder() .baseUrl("http://localhost:18899") //需要调用的服务的基础地址 .build(); } UserInfoServiceuserInfoService() { HttpServiceProxyFactoryhttpServiceProxyFactory=HttpServiceProxyFactory.builder(WebClientAdapter.forClient(webClient())) .build(); returnhttpServiceProxyFactory.createClient(UserInfoService.class); } }
上述配置完成,就需要在UserInfoService业务类中定义调用的接口信息了。
"") (publicinterfaceUserInfoService { "/userinfo") (Stringuserinfo(Stringname); url="/userlist") (List<User>userlist(Paginationpagination); }
通过@HttpExchange,@GetExchange和@PostExchange可以定位到方法需要调用的具体地址,以userinfo为例,其请 求的地址就是http://localhost:18899/userinfo?name=xxxx。下面就是通过测试类调用该接口。
classes= {Springboot26DemoApplication.class}) (SpringRunner.class) (publicclassClientApplicationTests { UserInfoServiceuserInfoService; publicvoiduserinfo() { Stringinfo=userInfoService.userinfo("bob"); System.out.println(info); } publicvoiduserList() { Paginationpagination=newPagination(); pagination.setPageSize(2); List<User>userList=userInfoService.userlist(pagination); System.out.println(userList); }
提供接口服务的服务端程序提供两个测试接口,如下:
publicclassHttpTestController { "/userinfo") (publicStringuserinfo(Stringname){ return"user info :"+name; } "/userlist") (publicList<User>userList(Paginationpagination){ List<User>userList=newArrayList<>(); for(inti=1;i<=5;i++){ Useruser=newUser(i,"username"+i,"name"+i,i); userList.add(user); } if(pagination.getPageSize()>5){ pagination.setPageSize(5); } returnuserList.subList(pagination.getPageIndex(), pagination.getPageSize()); } }
在此就可以完成了这个新特性的使用。根据官方给予的文档和demo可以实现更多的场景调用,后面继续研究。在这里主 要有两个说明,一个就是WebClient的注入,本人理解主要就是区分不同进程服务,如果存在多个,需要注入多WebClient,业务接口上createClient的时候注入不同的WebClient即可,当然这部分的地址配置需要放到配置文件中,做成可配置的比较合理。还有一点就是连接复用问题,网络上已经有相关的文章说明如何配置连接池参数,做资源最大化利用的处理,读者可以自行去试验。最后一点就是返回值的赋值问题,如果客户端定义的po中属性比接口方提供的多,那么做属性赋值时,多出来的属性赋值,string类型的会赋值为'null',这点感觉很奇怪,可能有配置可以解决这个问题。
总体感觉Spring6提供的这个新特性还是比较简洁方便的,其他方面再做研究。