• RestTemplate今天过去将来


    • RestTemplate 是一个 HTTP 客户端,由 Spring 团队按照 RestFul 风格约束进行进一步抽象封装,便于开发者调用。
    • 在 spring 发展过程中,在 spring5 里,spring 团队提出并推介了一个新的 Http 客户端: webClient, 并说明 RestTemplate 将在未来的版本中弃用,并且未来不会添加主要的新功能
    • 本文会讲解 RestTemplate如何使用,以及如何使用 Apache HttpClient 和 OKHttp去替换其内部实现

    本文适合阅读对象:项目中依然使用了 RestTemplate 作为客户端的开发人员。或者有需要使用 Apache HttpClient 或者 OKHttp 这一类 HTTP 工具库的开发人员。
    在这里插入图片描述

    RestTemplate 使用

    内部实现:RestTemplate 默认使用 JDK 自带的 HttpURLConnection 作为底层 HTTP 客户端实现。它是一个同步阻塞库,每一个 Http 请求都会创建一个线程

    RestTemplate 使用: 使用 发送 Http 请求非常简单。需要三步,引入依赖,设置配置 Bean,然后使用

    1. 引入依赖
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    1. 设置配置类 Bean
    @Configuration
    public class ApplicationContextConfig {
    
        @Bean
        @ConditionalOnMissingBean
        public RestTemplate getRestTemplate() {
            return new RestTemplate();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 使用
    @Slf4j
    @RestController
    @RequestMapping("/consumer")
    public class OrderController {
        public static String PAYMENT_URL = "http://localhost:8001";
    
        @Autowired
        private RestTemplate restTemplate;
    
        @PostMapping("/payment/insert")
        public AjaxResult<Void> callPaymentInsert() {
    
            PaymentEntity payment = new PaymentEntity();
            payment.setId(1L);
            payment.setSerial("123456");
    
            log.info("执行前-----------");
            restTemplate.postForObject(PAYMENT_URL + "/payment/insertOne", payment, AjaxResult.class);
            log.info("执行后-----------");
            return new AjaxResult<>(200, "success");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    webClient 使用

    既然 spring 团队已经不推介使用 RestTemplate, 那么在 spring5 中力推的 webClient HTTP 客户端应该如何使用?

    内部实现: webClient 使用 Spring Reactive 框架内部提供的异步,非阻塞解决方案。

    webClient 使用: 使用需要两步,引入依赖,替换 RestTemplate 内部 HTTP 实现,然后使用

    webClient 作为新一代的 HTTP 客户端,不光支持非阻塞方法,也支持与 RestTemplate 类似的阻塞方案。

    1. 引入依赖
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webfluxartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    1. 使用 webClient(非阻塞方式)
    @Slf4j
    @RestController
    @RequestMapping("/consumer")
    public class OrderController {
        public static String PAYMENT_URL = "http://localhost:8001";
    
        @Autowired
        private RestTemplate restTemplate;
    
        @PostMapping("/payment/insert2")
        public AjaxResult<Void> callPaymentInsert() {
    
            PaymentEntity payment = new PaymentEntity();
            payment.setId(1L);
            payment.setSerial("123456");
    
            log.info("执行前-----------");
            Flux<AjaxResult> paymentEntityFlux = WebClient.create()
                    .method(HttpMethod.POST)
                    .uri(PAYMENT_URL + "/payment/insertOne")
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(BodyInserters.fromValue(payment))
                    .retrieve()
                    .bodyToFlux(AjaxResult.class);
            log.info("执行后-----------");
            paymentEntityFlux.subscribe(System.out::println);
            return new AjaxResult<>(200, "success");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    当然 webClient 也可以使用阻塞方式, 区别在于 body 方法 bodyToMono(),以及返回值

    @Slf4j
    @RestController
    @RequestMapping("/consumer")
    public class OrderController {
        public static String PAYMENT_URL = "http://localhost:8001";
    
        @PostMapping("/payment/insert3")
        public AjaxResult<Void> callWebClientMono() {
    
            PaymentEntity payment = new PaymentEntity();
            payment.setId(1L);
            payment.setSerial("123456");
    
            log.info("执行前-----------");
            Mono<AjaxResult> resp = WebClient.create()
                    .method(HttpMethod.POST)
                    .uri(PAYMENT_URL + "/payment/insertOne")
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(BodyInserters.fromValue(payment))
                    .retrieve()
                    .bodyToMono(AjaxResult.class);
    
            System.out.println(resp.block());
            log.info("执行后-----------");
    
            return new AjaxResult<>(200, "success");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    okhttp

    技术发展真的挺快,仅仅几年时间过去,项目中必用的 RestTemplate 竟然已经有点渐渐不再被人问津。好在其封装非常的抽象,非常方便我们去替换内部实现。
    作为开发人员可以依旧使用熟悉的 restTemplate 去调用,而其内部实现被我们悄悄替换为更为高效的实现.

    从开发人员的反馈,和网上的各种 HTTP 客户端性能以及易用程度评测来看.

    • OkHttp3 优于 Apache HttpClient 4
    • Apache HttpClient 4 优于 HttpURLConnection

    而 RestTemplate 内部由 HttpURLConnection 实现,效率不如 OkHttp , 所以我们可以使用 OkHttp 替换其 RestTemplate 的内部实现 HttpURLConnection,来优化 Http 效率

    • 使用 OkHttpClient 作为底层客户端
    1. 引入依赖
    <dependency>
      <groupId>com.squareup.okhttp3groupId>
      <artifactId>okhttpartifactId>
      <version>4.10.0version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 替换 RestTemplate 内部实现
    @Configuration
    public class ApplicationContextConfig {
    
      @Bean
      @ConditionalOnMissingBean
      public RestTemplate getRestTemplate() {
          return new RestTemplate(getOkHttpRequestFactory());
      }
    
      private ClientHttpRequestFactory getOkHttpRequestFactory() {
          return new OkHttp3ClientHttpRequestFactory();
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 上下对比一下,使用 OKHttp 替换 RestTemplate 内部实现是不是非常简单?
    • 仅仅需要向 RestTemplate 构造函数中传入 OkHttp 实例即可。Spring 的抽象封装就是如此强大。
    • 当然我们还可以对 Okttp 额外做一些其他的设置,比如使用线程池,设置超时时间,设置代理,设置监听器等等。你可以继续探索。
    @Configuration
    public class ApplicationContextConfig {
    
      @Bean
      @ConditionalOnMissingBean
      public RestTemplate getRestTemplate() {
          return new RestTemplate(getOkHttpRequestFactory());
      }
    
      private ClientHttpRequestFactory getOkHttpRequestFactory() {
        // 线程池
        ConnectionPool pool = new ConnectionPool(30, 300L, TimeUnit.MINUTES);
    
        OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
                .connectionPool(pool)
                .connectTimeout(10L, TimeUnit.SECONDS)
                .readTimeout(10L, TimeUnit.SECONDS)
                .writeTimeout(10L, TimeUnit.SECONDS)
                // .hostnameVerifier((hostname, session) -> true)
                // 设置代理
                // .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 9000)))
                // 拦截器
                // .addInterceptor()
                .build();
    
        return new OkHttp3ClientHttpRequestFactory(okHttpClient);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    Apache HttpClient 5

    • Apache HttpClient 的版本在 4+ 和 5+ 版本上有非常大的区别。目前 4+ 版本已经停止更新,网上相关文章基本都是使用的 4+版本。文末有关于 4 的阅读资料

    • 我们使用 4+ 最新版本 4.5.13,因为 5+ 版本无法替换,2 年多过去了,官方很可能不再打算支持

    • 在常见的 4+版本中,替换 restTemplate 内核必须用到一个类 HttpComponentsClientHttpRequestFactory,而它是在 Common HttpClient 的基础上封装而成,官方文档已经强烈不建议使用《4.3 ,所以市面上上关于 Apache HttpClient 版本低于 4.3 的 的实现都可以抛弃了。

    • 由于它也是 HTTP 的标准实现,所以与 OKHttp 一样,替换 RestTemplate 内部实现,就像喝水一样简单,

    1. 引入 4.5.13 依赖
    <dependency>
        <groupId>org.apache.httpcomponents.client5groupId>
        <artifactId>httpclient5artifactId>
        <version>5.1.2version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 替换 RestTemplate 内部 HTTP 实现
    @Configuration
    public class ApplicationContextConfig {
    
      @Bean
      @ConditionalOnMissingBean
      public RestTemplate getRestTemplate() {
          return new RestTemplate(getApacheHttpClientRequestFactory());
      }
        private ClientHttpRequestFactory getApacheHttpClientRequestFactory() {
    
            BasicHttpClientConnectionManager connectionManager =
                    new BasicHttpClientConnectionManager();
    
            HttpClient httpClient = HttpClients.custom()
                    .setConnectionManager(connectionManager).build();
    
            return  new HttpComponentsClientHttpRequestFactory(httpClient);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    中间遇到的挑战

    在查阅 httpclient5 实现 RestTemplate 的过程中耗费了较长时间。

    1. 要实现 RestTemplate ,必须实现 RestTemplate 的 ClientHttpRequestFactory 接口 ,在 httpclient4 中 ,对这个接口的实现类是HttpComponentsClientHttpRequestFactory
    2. 在 httpclient5 中,官方团队 2 年过去了,还没有实现这个类 HttpComponentsClientHttpRequestFactory, 因此导致了 httpclient5 无法实现 RestTemplate.
    3. 目前看来官方并不打算重新实现这个类了,所以只能使用 4.5.13(4+最新版本)来实现

    资料阅读

  • 相关阅读:
    java游戏制作-拼图游戏
    好心情:别在该躺平的时候动脑子,10种方法让大脑高效休息
    【软考软件评测师】自动化测试章节下篇
    常用 CMD 命令
    你以为搞个流水线每天跑,团队就在使用CI/CD实践了?
    【虚拟机】VMware的NAT模式、桥接模式、仅主机模式
    万界星空科技MES系统软件体系架构及应用
    每日一记 关于Python的准备知识、快速上手
    【CTF】crypto ECC 小计
    Sql知识总结-MySql存储过程
  • 原文地址:https://blog.csdn.net/win7583362/article/details/126458975