java远程调用之RPC协议与HTTP协议对比分析

5. 调用的()、( name)等方法可获取服务器的响应头;调用的()方法可获取对象,该对象包装了服务器的响应内容 。程序可通过该对象获取服务器的响应内容 。
6. 释放连接 。无论执行方法是否成功,都必须释放连接 。
下面是一个简单的例子,演示了如何使用发送GET请求并处理响应的过程
import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.util.EntityUtils;public class HttpClientExample {public static void main(String[] args) throws Exception {// 创建HttpClient对象CloseableHttpClient httpClient = HttpClients.createDefault();// 创建HttpGet请求对象HttpGet httpGet = new HttpGet("http://www.example.com/");// 执行Http请求CloseableHttpResponse response = httpClient.execute(httpGet);// 处理Http响应int statusCode = response.getStatusLine().getStatusCode();String responseBody = EntityUtils.toString(response.getEntity());System.out.println("Status Code: " + statusCode);System.out.println("Response Body: " + responseBody);// 关闭Http连接response.close();httpClient.close();}}
简介
先简单介绍一下:
是提供的一个用于发送 HTTP 请求的模板类,它简化了在 Java 应用中进行服务调用的过程 。注意与不同,它只能在框架中使用,并且主要在单体架构中使用,或者是需要更多自定义配置的场景 。在微服务中远程调用的实现方案是下面的要介绍的Feign 。
提供了一组方便的方法,可以用于发送 GET、POST、PUT、 等不同类型的 HTTP 请求,并支持对请求和响应进行自定义配置和处理 。
特点和功能
支持多种 HTTP 请求方法: 提供了多个方法,如 ()、()、put()、() 等,用于发送不同类型的 HTTP 请求 。你可以根据实际需要选择合适的方法来发送请求 。
支持请求参数传递: 允许将请求参数作为 URL 查询参数、路径参数、请求体或者请求头的方式进行传递 。你可以通过方法的参数或者使用 、 等对象来设置请求参数 。
支持请求和响应的自定义配置:你可以通过设置的属性、拦截器、消息转换器等来自定义请求和响应的处理 。例如,你可以设置超时时间、设置请求头、添加认证信息,以及指定响应的数据类型等 。
支持响应的处理和转换: 可以将响应的数据转换成指定的数据类型,如将 JSON 数据转换成 Java 对象、XML 数据转换成对象等 。你可以使用自带的消息转换器,也可以自定义消息转换器来处理响应数据 。
集成了的异常处理机制:当发生 HTTP 请求错误时,会根据 HTTP 响应状态码抛出相应的异常,例如 tion、tion 等,你可以捕获这些异常并进行处理 。
使用步骤 1.引入依赖
org.springframework.bootspring-boot-starter-web
2.创建对象,交由容器进行管理
列举常见的创建方式
1.启动类中注入对象
package com.example.demo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Bean;import org.springframework.web.client.RestTemplate;@SpringBootApplicationpublic class DemoApplication {@Beanpublic RestTemplate getRestTemplate(){return new RestTemplate();}public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}}
2.创建配置类,注入的对象
package com.czxy.ssm.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.client.RestTemplate;/*** RestTemplate工具类,主要用来提供RestTemplate对象*/@Configuration//加上这个注解作用,可以被Spring扫描public class RestTemplateConfig {/*** 创建RestTemplate对象,将RestTemplate对象的生命周期的管理交给Spring*/@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}}
3.创建配置类,注入的对象,并设置连接和请求的时间
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.http.client.ClientHttpRequestFactory;import org.springframework.http.client.SimpleClientHttpRequestFactory;import org.springframework.web.client.RestTemplate;/*** RestTemplate工具类,主要用来提供RestTemplate对象*/@Configuration//加上这个注解作用,可以被Spring扫描public class RestTemplateConfig {@Beanpublic RestTemplate restTemplate(ClientHttpRequestFactory factory){return new RestTemplate(factory);}@Beanpublic ClientHttpRequestFactory simpleClientHttpRequestFactory(){SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();factory.setReadTimeout(500000);//单位为msfactory.setConnectTimeout(500000);//单位为msreturn factory;}}
3.接口调用 3.1 简单Get\Post请求
@Testpublic void testGetPost(){RestTemplate restTemplate = new RestTemplate();restTemplate.getMessageConverters().add(new FastJsonHttpMessageConverter());String res = restTemplate.postForObject("http://test.aihe.space/", null, String.class);System.out.println(res);String res2 = restTemplate.getForObject("http://test.aihe.space/",String.class);System.out.println(res2);}

java远程调用之RPC协议与HTTP协议对比分析

文章插图
3.2 Post提交常规表单
@Testpublic void testGetPost(){RestTemplate restTemplate = new RestTemplate();restTemplate.getMessageConverters().add(new FastJsonHttpMessageConverter());String res = restTemplate.postForObject("http://test.aihe.space/", null, String.class);System.out.println(res);String res2 = restTemplate.getForObject("http://test.aihe.space/",String.class);System.out.println(res2);}
3.3 Post上传文件
@Testpublic void testPostFile(){RestTemplate restTemplate = new RestTemplate();HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.MULTIPART_FORM_DATA);MultiValueMap map= new LinkedMultiValueMap<>();map.add("id", "1");map.add("file",new FileSystemResource("/Users/aihe/code/init/src/test/java/me/aihe/RestTemplateTest.java"));HttpEntity request = new HttpEntity<>(map, headers);String fooResourceUrl = "http://test.aihe.space/";ResponseEntity response = restTemplate.postForEntity(fooResourceUrl, request, String.class);System.out.println(response.getStatusCode());System.out.println(response.getBody());}
3.4添加和
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl("127.0.0.1:8080").path("/test").build(true);URI uri = uriComponents.toUri();RequestEntity requestEntity = RequestEntity.post(uri).// 添加 cookie(这边有个问题,假如我们要设置 cookie 的生命周期,作用域等参数我们要怎么操作)header(HttpHeaders.COOKIE,"key1=value1").// 添加 headerheader(("MyRequestHeader", "MyValue")accept(MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_JSON).body(requestParam);ResponseEntity responseEntity = restTemplate.exchange(requestEntity,JSONObject.class);// 响应结果JSONObject responseEntityBody = responseEntity.getBody();
Feign 简介
Feign是一个声明式、模板化的HTTP客户端框架,它简化了使用HTTP请求和响应的过程 。它是开源的一部分,旨在帮助开发人员轻松地构建基于HTTP的客户端 。
Feign远程调用基本流程
Feign远程调用,核心就是通过一系列的封装和处理,将以JAVA注解的方式定义的远程调用API接口,最终转换成HTTP的请求形式,然后将HTTP的请求的响应结果,解码成JAVA Bean,放回给调用者 。Feign远程调用的基本流程,大致如下图所示
从上图可以看到,Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求 。通过Feign以及JAVA的动态代理机制,使得Java 开发人员,可以不用通过HTTP框架去封装HTTP请求报文的方式,完成远程服务的HTTP调用 。
使用步骤 1.引入依赖
org.springframework.cloudspring-cloud-starter-openfeign
2. 添加注解
在客户端的服务模块的启动类上添加注解@开启Feign的功能
3.编写Feign的客户端
在客户端的服务模块中新建一个接口,下面举个例子
package com.kjz.order.client;import com.kjz.order.pojo.User;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;@FeignClient("userservice")public interface UserClient {@GetMapping("/user/{id}")User findById(@PathVariable("id") Long id);}
这个客户端主要是基于的注解来声明远程调用的信息,比如:
这样,Feign就可以帮助我们发送http请求,无需自己使用来发送了 。
与Feign对比
为什么中使用使用Feign进行远程调用而不使用呢?
我认为主要有以下原因:
声明式接口:Feign 允许你使用注解方式定义接口,将服务调用的细节隐藏在接口之后,使得代码更加简洁、易读 。相比之下,需要显式地构建请求和处理响应,代码量较多且容易出错,参数复杂URL难以维护。
与服务注册中心的集成:Feign 可以与Cloud 提供的服务注册中心(如 、)无缝集成,从而自动获取服务实例列表并基于负载均衡策略进行调用 。而需要手动编写逻辑来实现服务发现和负载均衡 。
支持断路器 :Feign 在设计时就考虑到了与断路器的紧密集成,可以方便地实现服务降级、熔断等容错机制 。而需要额外的配置和集成工作才能与整合 。
更好的扩展性:Feign 的设计理念是可以轻松地与其他Cloud 组件进行集成 。它支持通过编写自定义的解码器、编码器和拦截器等来扩展其功能 。而在这方面的扩展性相对较差 。
如何在两者间做出选择
由于HTTP与RPC不是一个并行的概念,所以也无法在两者间做选择 。这里我浅谈一下RPC的一种实现方案Dubbo与Feign之间该如何做出选择 。
使用场景
Feign 是一种声明式的 HTTP 客户端,用于简化对API 的调用 。它的主要使用场景是在微服务架构中,通过 HTTP 协议调用其他服务的API 。Feign 支持多种编解码器,如 、Gson、JAXB 等,可以将请求和响应转换成对象 。Feign 还提供了负载均衡和服务发现功能,可以通过 、 等服务注册中心来自动发现和负载均衡服务 。
Dubbo 是一种基于 RPC(Call)协议的远程调用框架,它可以将远程调用抽象成本地调用的方式 。Dubbo 的主要使用场景是在大型分布式系统中,通过 RPC 协议调用其他服务 。Dubbo 支持多种协议,如 Dubbo 协议、HTTP 协议、 协议等 。Dubbo 还提供了负载均衡、服务治理、容错等功能,可以通过 、 等服务注册中心来实现服务发现和负载均衡 。
实际应用
Feign 和 Dubbo 都是目前广泛应用于微服务架构的远程调用框架 。
Feign 可以与Cloud 等微服务框架集成,通过注解方式声明远程调用接口,例如:
?@FeignClient(name = "users-service")public interface UsersClient {@GetMapping("/users/{id}")User getUser(@PathVariable("id") Long id);}?
这个接口定义了一个名为users-的远程服务,通过@注解来指定远程调用的路径 。Feign 会根据注解生成代理对象,调用代理对象的方法就会触发远程调用 。Feign 还支持熔断器,可以防止服务雪崩 。
Dubbo 也可以与Cloud 等微服务框架集成,通过注解方式声明远程调用接口,例如:
@Servicepublic interface UserService {User getUser(Long id);}
这个接口定义了一个名为的远程服务,Dubbo 会自动将这个接口暴露成远程服务,其他服务可以通过 Dubbo 的客户端调用这个接口 。Dubbo 还提供了丰富的配置选项,可以配置负载均衡算法、容错策略、超时时间等 。同时,Dubbo 还支持服务降级和熔断,可以在服务不可用时自动切换到备用服务 。
原理
Feign 是基于动态代理和注解实现的 。当应用程序调用 Feign 客户端接口时,Feign 会在运行时动态地生成一个代理对象,代理对象通过注解来获取远程服务的信息,然后将远程调用转化为 HTTP 请求,发送给远程服务 。Feign 通过编解码器将请求和响应转换成对象 。
Dubbo 是基于 RPC 协议实现的 。当应用程序调用 Dubbo 服务时,Dubbo 会将调用信息封装成一个 RPC 请求,然后通过网络传输到远程服务,远程服务将 RPC 请求解码,执行对应的方法,然后将执行结果封装成 RPC 响应,通过网络传输回来 。Dubbo 支持多种协议,可以选择最适合当前场景的协议 。
性能
Feign 和 Dubbo 的性能各有优劣 。Feign 的性能相对较差,因为它是基于 HTTP 协议实现的,每次远程调用都需要建立 TCP 连接,开销比较大 。而 Dubbo 的性能相对较好,因为它是基于 RPC 协议实现的,每次远程调用只需要发送一个小的二进制请求,响应也是一个小的二进制数据包,开销比较小 。
另外,Dubbo 还提供了多种负载均衡算法和容错策略,可以在服务负载均衡和故障恢复方面更加灵活和高效 。
总结
Feign 和 Dubbo 都是优秀的微服务架构下的远程调用框架,各有特点 。Feign 适合调用API 接口,具有简单、轻量、易用等特点 。Dubbo 适合大规模分布式系统,具有高性能、丰富的配置、容错机制等特点 。在实际应用中,需要根据具体场景选择合适的远程调用框架 。对于简单的微服务应用场景,Feign 可以轻松实现服务之间的远程调用,而且使用起来非常方便,无需过多的配置和代码编写 。但是,如果要实现高性能、高可用的大规模分布式系统,Dubbo 更适合 。
此外,需要注意的是,Feign 和 Dubbo 虽然都是远程调用框架,但其实现方式不同,也有着不同的使用场景和局限性 。Feign 仅支持 HTTP 协议,不支持 RPC 协议,也不支持自定义协议 。而 Dubbo 支持多种协议,并且提供了丰富的配置选项,可以根据实际需要进行灵活配置 。
【java远程调用之RPC协议与HTTP协议对比分析】因此,在选择 Feign 和 Dubbo 时,需要根据实际情况进行综合考虑,包括应用场景、性能需求、安全性、易用性等多个方面 。同时,还需要根据具体业务需求和技术栈进行权衡和选择,以便最终达到最优的性能和效果 。