(1)实现微服务间服务的调用——RestTemplate

1、引言

以往单体应用在单机中进行进程内通信,稳定性相当好。但修改为分布式系统,变为进程间通信,就需要跨设备的网络访问,由于微服务化后,每个微服务系统都对外暴露REST风格的访问接口,因此服务间的通信一般都是通过发起http请求RESTful接口完成的。
在这里插入图片描述
在日常工作中,主要有以下方式:

  • HttpURLConnection(java内置的,过于原始,低效)
  • HttpClient
  • OKHttp
  • RestTemplate
  • Feign

HttpURLConnection、HttpClient、OKHttp都需要繁琐的编码,使用较少。RestTemplate和Feign相对简单,是常用的方式。

2、RestTemplate

RestTemplate : Spring 提供的用于访问 Rest 服务的客户端,其提供了多种便捷访问远程 HTTP 服务的方法,大大提高客户端的编写效率。

使用方法(spring提供,不需要格外依赖)

//proxyBeanMethods = false:轻量级模式,用来优化配置性能
@Configuration(proxyBeanMethods = false)
public class RestTemplateConfig {
   //使用时注入该bean对象即可使用其方法访问远程服务 
   @Bean
   public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder){
       return restTemplateBuilder.build();
   }
}

2.1、核心方法

getForObject()、postForObject方法设置返回值类型,会返回该类型的返回值

put()、delete()方法摒弃了方法的返回值

getForEntity、postForEntity方法会返回ResponseEntity对象,该对象在响应结果基础上包装了响应状态码和响应头

exchange():自定义(底层用的麻烦,用的少),例:put请求并提供返回值

使用

@SpringBootTest
class RestTemplateTestApplicationTests {
   
   @Autowired
   private RestTemplate restTemplate;
   public static final String URI="http://localhost:8080";

   //get和delete请求,请求体不能携带数据,只能使用url传值
   //put和post请求,可以在url传值,也可以在请求体传值
   //url传值:使用 k=v  或   可变长参数或map(替换{}占位符)
   //请求体传值:使用HttpEntity对象等
   
   @Test
   public void testGet(){
       //发送get请求(指定url和方法返回值类型,可指定url参数)
       //restTemplate.getForObject(URI+"/rest/get?username=小明",String.class);
       //restTemplate.getForObject(URI + "/rest/get?username={username}", String.class, "小李");
       Map<String,String> map=new HashMap<>();
       map.put("username","小白");
       restTemplate.getForObject(URI + "/rest/get?username={username}", String.class,map);
   }
   
   @Test
   public void testDelete(){
       //delete方法丢弃了返回值
       restTemplate.delete(URI + "/rest/delete?username={username}", "小花");
   }
   
   @Test
   public void testPost(){
       //发送Post请求(指定url,请求体内容和方法返回值类型,可指定url参数)
       //创建httpheaders,并设置请求中内容类型
       HttpHeaders headers=new HttpHeaders();
       headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
       //准备请求参数    MultiValueMap<k,v> ==》 Map<k,List<v>>
       MultiValueMap<String,String> map=new LinkedMultiValueMap<>();
       map.add("username","小红");
       map.add("password","123456");
       //构建请求实体对象
       HttpEntity<MultiValueMap<String,String>> entity=new HttpEntity<>(map,headers);
       User user = restTemplate.postForObject(URI + "/rest/post?age={age}", entity, User.class, 20);
       System.out.println(user);
   }
   
   @Test
   public void testPostJson(){
       //发送Post请求(指定url,请求体内容和方法返回值类型,可指定url参数)
       //创建httpheaders,并设置请求中内容类型
       HttpHeaders headers=new HttpHeaders();
       headers.setContentType(MediaType.APPLICATION_JSON);
       //构建请求实体对象
       HttpEntity<Object> entity = new HttpEntity<>(new User("小蓝","123123"),headers);
       User user = restTemplate.postForObject(URI + "/rest/postjson?age={age}", entity, User.class, 21);
       System.out.println(user);

       //简单写法:
       //restTemplate.postForObject(URI + "/rest/postjson?age={age}",new User("小蓝","123123") , User.class, 21);
   }
   
   @Test
   public void testPut(){
       //put方法丢弃了返回值
       restTemplate.put(URI + "/rest/put", new User("小蓝","123123"), User.class);
   }
   
   @Test
   public void testPostForEntity(){
       ResponseEntity<User> entity = restTemplate.postForEntity(URI + "/rest/postjson?age={age}", new User("小蓝", "123123"), User.class, 21);
       System.out.println("响应状态码"+entity.getStatusCodeValue());
       System.out.println("响应结果:"+entity.getStatusCode().getReasonPhrase());
       System.out.println("响应体:"+entity.getBody());
   }
   
   @Test
   public void testExchange(){
       //自定义(底层用的麻烦,用的少),例:put请求并提供返回值
       //创建httpheaders,并设置请求中内容类型
       HttpHeaders headers=new HttpHeaders();
       headers.setContentType(MediaType.APPLICATION_JSON);
       //构建请求实体对象
       HttpEntity<Object> entity = new HttpEntity<>(new User("小黑","123123"),headers);
       ResponseEntity<User> response = restTemplate.exchange(URI + "/rest/put", HttpMethod.PUT, entity, User.class);
       System.out.println(response.getBody());
   }
}

2.2、切换底层通信组件

RestTemplate只是对其他的HTTP客户端的封装,其本身并没有实现HTTP相关的基础功能。其底层通信组件的实现是可以配置切换的,RestTemplate 默认支持三种HTTP客户端库:

  • SimpleClientHttpRequestFactory。对应的HTTP库是java JDK自带的HttpURLConnection,这是默认使用的通信组件。
  • HttpComponentsAsyncClientHttpRequestFactory。对应的HTTP库是Apache HttpComponents(包含HttpClient)。
  • OkHttp3ClientHttpRequestFactory。对应的HTTP库是OkHttp3。

    从开发人员的反馈,和网上的各种HTTP客户端性能以及易用程度评测来看,OkHttp3略优
使用OKHttp3
  1. 导入okhttp3依赖
  <dependency>
      <groupId>com.squareup.okhttp3</groupId>
      <artifactId>okhttp</artifactId>
      <version>4.8.1</version>
  </dependency>
  1. 通过设置setRequestFactory方法,切换底层实现
  @Configuration(proxyBeanMethods = false)
  public class RestTemplateConfig {
      @Bean
      public RestTemplate restTemplate(RestTemplateBuilder builder){
          //切换底层通信组件为okhttp3  注意restTemplateBuilder为不可变对象,每次修改会返回新的builder,需要重新赋值
         	builder = builder.requestFactory(()->{
              OkHttp3ClientHttpRequestFactory httpRequestFactory = new OkHttp3ClientHttpRequestFactory();
              httpRequestFactory.setConnectTimeout(3000);//设置建立连接的超时时间
              httpRequestFactory.setReadTimeout(5000);//设置读取数据的超时时间
              httpRequestFactory.setWriteTimeout(5000);//设置写出数据的超时时间
              return httpRequestFactory;
          });
          return builder.build();
      }
  }

2.3、使用拦截器

有一些场景需要对请求进行统一处理,如:向请求中添加统一的请求头对请求进行拦截、根据需要改写请求URL。

拦截器的开发步骤

  1. 实现ClientHttpRequestInterceptor接口
  public class MyClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
      @Override
      /**
       * @param request 请求对象,通过它可以获取请求的URI、请求方式和请求头
       * @param body 随请求发送的请求体
       * @param execution 执行请求的工具
       */
      public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
          System.out.println("拦截器开发");
          //发送请求
          ClientHttpResponse response = execution.execute(request, body);
          return response;
      }
  }
  1. 配置自定义拦截器生效
@Configuration(proxyBeanMethods = false)
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder){
        builder=builder.additionalInterceptors(new MyClientHttpRequestInterceptor());
        return builder.build();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值