首页 >> 大全

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

2023-12-14 大全 20 作者:考证青年

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;@SpringBootApplication
public 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协议对比分析__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 等微服务框架集成,通过注解方式声明远程调用接口,例如:

@Service
public 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 支持多种协议,并且提供了丰富的配置选项,可以根据实际需要进行灵活配置。

因此,在选择 Feign 和 Dubbo 时,需要根据实际情况进行综合考虑,包括应用场景、性能需求、安全性、易用性等多个方面。同时,还需要根据具体业务需求和技术栈进行权衡和选择,以便最终达到最优的性能和效果。

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了