RPC(Remote Procedure Call):远程过程调用
本地过程调用: a(); b(); a() { b();}: 不同方法都在同一个JVM运行
远程过程调用:
服务提供者:
服务消费者:
通过连接对方服务器进行请求\响应交互,来实现调用效果
API/SDK的区别是什么?
api:接口(Application Programming Interface)
远程提供功能;
sdk:工具包(Software Development Kit)
导入jar包,直接调用功能即可
开发过程中,我们经常需要调用别人写的功能
如果是内部微服务,可以通过依赖cloud、注册中心、openfeign等进行调用
如果是外部暴露的,可以发送 http 请求、或遵循外部协议进行调用
SpringBoot 整合提供了很多方式进行远程调用
轻量级客户端方式
RestTemplate: 普通开发
WebClient: 响应式编程开发
Http Interface: 声明式编程
Spring Cloud分布式解决方案方式
Spring Cloud OpenFeign
第三方框架
Dubbo
gRPC
...
1. WebClient
非阻塞、响应式HTTP客户端
1.1 创建与配置
发请求:
请求方式: GET\POST\DELETE\xxxx
请求路径: /xxx
请求参数:aa=bb&cc=dd&xxx
请求头: aa=bb,cc=ddd
请求体:
创建 WebClient 非常简单:
WebClient.create()
WebClient.create(String baseUrl)
还可以使用 WebClient.builder() 配置更多参数项:
uriBuilderFactory: 自定义UriBuilderFactory ,定义 baseurl.
defaultUriVariables: 默认 uri 变量.
defaultHeader: 每个请求默认头.
defaultCookie: 每个请求默认 cookie.
defaultRequest: Consumer 自定义每个请求.
filter: 过滤 client 发送的每个请求
exchangeStrategies: HTTP 消息 reader/writer 自定义.
clientConnector: HTTP client 库设置.
//获取响应完整信息
WebClient client = WebClient.create("https://example.org");
1.2 获取响应
retrieve()方法用来声明如何提取响应数据。比如
//获取响应完整信息
WebClient client = WebClient.create("https://example.org");
Mono<ResponseEntity<Person>> result = client.get()
.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
.retrieve()
.toEntity(Person.class);
//只获取body
WebClient client = WebClient.create("https://example.org");
Mono<Person> result = client.get()
.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(Person.class);
//stream数据
Flux<Quote> result = client.get()
.uri("/quotes").accept(MediaType.TEXT_EVENT_STREAM)
.retrieve()
.bodyToFlux(Quote.class);
//定义错误处理
Mono<Person> result = client.get()
.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
.retrieve()
.onStatus(HttpStatus::is4xxClientError, response -> ...)
.onStatus(HttpStatus::is5xxServerError, response -> ...)
.bodyToMono(Person.class);
1.3 定义请求体
//1、响应式-单个数据
Mono<Person> personMono = ... ;
Mono<Void> result = client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.body(personMono, Person.class)
.retrieve()
.bodyToMono(Void.class);
//2、响应式-多个数据
Flux<Person> personFlux = ... ;
Mono<Void> result = client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_STREAM_JSON)
.body(personFlux, Person.class)
.retrieve()
.bodyToMono(Void.class);
//3、普通对象
Person person = ... ;
Mono<Void> result = client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(person)
.retrieve()
.bodyToMono(Void.class);
2. HTTP Interface
Spring 允许我们通过定义接口的方式,给任意位置发送 http 请求,实现远程调用,可以用来简化 HTTP 远程访问。需要webflux场景才可
2.1 导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
2.2 定义接口
public interface BingService {
@GetExchange(url = "/search")
String search(@RequestParam("q") String keyword);
}
2.3 创建代理&测试
@SpringBootTest
class Boot05TaskApplicationTests {
@Test
void contextLoads() throws InterruptedException {
//1、创建客户端
WebClient client = WebClient.builder()
.baseUrl("https://cn.bing.com")
.codecs(clientCodecConfigurer -> {
clientCodecConfigurer
.defaultCodecs()
.maxInMemorySize(256*1024*1024);
//响应数据量太大有可能会超出BufferSize,所以这里设置的大一点
})
.build();
//2、创建工厂
HttpServiceProxyFactory factory = HttpServiceProxyFactory
.builder(WebClientAdapter.forClient(client)).build();
//3、获取代理对象
BingService bingService = factory.createClient(BingService.class);
//4、测试调用
Mono<String> search = bingService.search("尚硅谷");
System.out.println("==========");
search.subscribe(str -> System.out.println(str));
Thread.sleep(100000);
}
}