今日分享开始啦,请大家多多指教~

RestTemplate 采纳 Java Servlet API,因而是阻塞式同步调用。相同,WebClient 是异步的,期待响应的同时不会阻塞正在执行的线程。只有在响应后果准备就绪时,才会发动告诉。

RestTemplate 依然有用武之地。非阻塞模式在某些场景下比阻塞办法占用系统资源要少得多,这时 WebClient 是一种更好的抉择。

一、WebClient

非阻塞式客户端。WebClient 应用 Spring Reactive Framework 所提供的异步非阻塞解决方案。

当 RestTemplate 为每个事件(HTTP 申请)创立一个新的线程时,WebClient 将为每个事件创立相似于“工作”。幕后,Reactive 框架将对这些 “工作” 进行排队,并仅在适当的响应可用时执行它们。

Reactive 框架应用事件驱动的体系结构。它提供了通过 Reactive Streams API 组合异步逻辑的办法。因而,与同步/阻塞办法相比,Reactive 能够应用更少的线程和系统资源来解决更多的逻辑。WebClient 是 Spring WebFlux 库的一部分。因而,咱们还能够应用晦涩的函数式 API 编写客户端代码,并将响应类型(Mono 和 Flux)作为申明来进行组合。

1.依赖

 <!--WebClient-->        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-webflux</artifactId>        </dependency>

2.创立

    @Test    void webclient01Create(){        WebClient webClient = WebClient.create();        Mono<String> mono = webClient                .get() //get申请                .uri(BASE_URI + "/test/get01")                .retrieve() //获取响应体                .bodyToMono(String.class); //格式化响应数据        log.info("{}",mono.block());    }
    @Test    void webclient02Create(){        WebClient webClient = WebClient.create(BASE_URI);        Mono<String> mono = webClient                .get()                .uri("/test/get01")// uri 会主动拼接                .retrieve()                .bodyToMono(String.class);        log.info("{}",mono.block());    }
    @Test    void webclient03Builder(){        WebClient webClient = WebClient.builder()                .baseUrl(BASE_URI)                .build();        Mono<String> mono = webClient                .get()                .uri("/test/get01")                .retrieve()                .bodyToMono(String.class);        log.info("{}",mono.block());    }

3.应用

    @Test    void webclient04(){        WebClient webClient = WebClient.builder()                .baseUrl(BASE_URI)                .build();        Mono<String> mono = webClient                .get()                .uri(uriBuilder -> uriBuilder                    .path("/test/get02")                    .queryParam("pageSize",10)                    .queryParam("pageNum",1)                    .build())                .retrieve()                .bodyToMono(String.class);        log.info("{}",mono.block());    }
    @Test    void webclient05(){        WebClient webClient = WebClient.builder()                .baseUrl(BASE_URI)                .build();        User user = User.builder().id("0000").password("0000").build();        Mono<User> userMono = webClient                .post()                .uri(uriBuilder -> uriBuilder.path("/test/post01").build())                .contentType(MediaType.APPLICATION_JSON)                .body(Mono.just(user),User.class)//                .header()                .retrieve()                .bodyToMono(User.class);        log.info("{}",userMono.block());    }

二、RestTemplate

阻塞式客户端。RestTemplate 应用了基于每个申请对应一个线程模型(thread-per-request)的 Java Servlet API。这意味着,直到 Web 客户端收到响应之前,线程都将始终被阻塞上来。而阻塞代码带来的问题则是,每个线程都耗费了肯定的内存和 CPU 周期。这些线程将耗尽线程池或占用所有可用内存。因为频繁的 CPU 上下文(线程)切换,咱们还会遇到性能降落的问题。

1.小技巧

办法名的第一局部示意HTTP申请类型,办法名的第二局部示意响应类型。例如:getForObject 示意执行GET申请并将响应转化成一个Object类型的对象。

利用RestTemplate封装客户端发送HTTP申请时,如果出现异常就会抛出 RestClientException 类型的异样;能够通过在创立RestTemplate对象的时候指定一个ResponseErrorHandler类型的异样解决类来解决这个异样

exchange 和 excute 这两个办法是通用的HTTP申请办法,而且这两个办法还反对额定的HTTP申请类型

RestTemplate默认应用JDK提供的包去建设HTTP连贯,当然,开发者也能够应用诸如 Apache HttpComponents, Netty, and OkHttp 去建设HTTP连

RestTemplate外部默认应用HttpMessageConverter来实现HTTTP messages 和 POJO 之间的转换,能够通过RestTemplate的成员办法 tMessageConverters(java.util.List<org.springframework.http.converter.HttpMessageConverter<?>>). 去批改默认的转换器

RestTemplate外部默认应用SimpleClientHttpRequestFactory创立HTTP连贯能够通过HttpAccessor.setRequestFactory(org.springframework.http.client.ClientHttpRequestFactory)去做相应的批改

每种办法都有3个重载办法,其中两个接管String类型的申请门路和响应类型、参数;另外一个接管URI类型的申请门路和响应类型

应用String类型的申请门路时,RestTemplate会主动进行一次编码,所以为了防止反复编码问题最好应用URI类型的申请门路

getForObject 和 getForEntity 的区别:后者能够获取到更多的响应信息,前者这能够获取到响应体的数据

2.示例

应用@Configuration 提前注入的 RestTemplate

2.1GET

不带申请参数的GET申请

服务端代码

客户端测试代码

带申请参数的GET申请

服务端代码

    /*     * 带申请参数的get申请     * @param pageSize     * @param pageNum     * @return String     */    @GetMapping("/get02")    public String get02(@RequestParam Integer pageSize, @RequestParam Integer pageNum) {        return "get02() ok,申请参数为:" + pageSize + "/" + pageNum;    }

客户端测试代码

带门路参数的GET申请

服务端代码

    /*     * 带门路参数的get申请     * @param id     * @return String     */    @GetMapping("/get03/{id}")    public String get03(@PathVariable("id") String id) {        return "get03() ok,门路参数为:" + id;    }

客户端测试代码

带有申请参数和门路参数的GET申请

服务端代码

    /*     * 带有申请参数和门路参数的get申请     * @param score     * @param id     * @return String     */    @GetMapping("/get04/{id}")    public String get04(@RequestParam String score, @PathVariable("id") String id) {        return "get04() ok,申请参数为:" + score + ",门路参数为:" + id;    }

客户端测试代码

带申请参数的GET申请,Map传递

服务端代码

    /*     * 带申请参数的get申请     * @param pageSize     * @param pageNum     * @return String     */    @GetMapping("/get02")    public String get02(@RequestParam Integer pageSize, @RequestParam Integer pageNum) {        return "get02() ok,申请参数为:" + pageSize + "/" + pageNum;    }

客户端测试代码

    @Test    void get05(){        Map<String,Object> params = new HashMap<>();        params.put("pageSize",10);        params.put("pageNum",1);        String uri = BASE_URI +"/test/get02?pageSize={pageSize}&pageNum={pageNum}";        String result = restTemplate.getForObject(uri,String.class,params);        log.info("{}",result);    }

不带申请参数的GET申请返回ResponseEntity

能够获取到残缺的响应信息

服务端代码

    /*     *  不带参数的get申请     * @return String     */    @GetMapping("/get01")    public String get01() {        return "get01() ok";    }

客户端测试代码

    @Test    void get06(){        String uri = BASE_URI + "/test/get01";        ResponseEntity<String> result = restTemplate.getForEntity(uri,String.class);        log.info("{}",result);    }

携带申请参数的GET申请,返回List<Entity>

服务器端代码

客户端测试代码

    @Test    void get07(){        String uri = BASE_URI + "/test/get05?pageSize={1}&pageNum={2}";        ResponseEntity<List> result = restTemplate.getForEntity(uri,List.class,10,1);        log.info("{}", result);    }

自定义申请头的GET申请

服务端代码

客户端测试代码

@Test    void get08(){        String uri = BASE_URI + "/test/get05?pageSize={1}&pageNum={2}";        HttpHeaders httpHeaders = new HttpHeaders();        httpHeaders.add("token", UUID.randomUUID().toString());        ResponseEntity<List> result = restTemplate.exchange(                uri,                HttpMethod.GET,                new HttpEntity<>(httpHeaders),                List.class,                10,1        );        log.info("{}",result);    }

2.2 POST

没有申请参数只有申请体的POST申请

服务端代码

    /*     * 只有申请体的POST申请     * @param user     */    @PostMapping("/post01")    public User post01(@RequestBody User user){        log.info("申请体:{}",user.toString());        return user;    }

客户端测试代码

含有申请体、申请参数、门路参数的POST申请

服务端代码

    /*     * 带有申请体参数、申请参数、门路参数的POST申请     * @param user     * @param status     * @param type     * @return String     */    @PostMapping("/post02/{type}")    public String post02(@RequestBody User user,                         @RequestParam("status") Integer status,                         @PathVariable("type") String type) {        return "requestBody:" + user.toString() + ",requestParam:" + status + ",      pathVariable:" + type + "";    }

客户端测试代码

    @Test    void post02() {        String uri = BASE_URI + "/test/post02/++++/?status={1}";        String result = restTemplate.postForObject(                uri,                User.builder().id("***").password("....").build(),                String.class,                0        );        log.info("{}",result);    }

应用HttpEntity自定义申请体和申请头发起POST申请

服务端代码

    /*     * 带有申请体参数、申请参数、门路参数的POST申请     * @param user     * @param status     * @param type     * @return String     */    @PostMapping("/post02/{type}")    public String post02(@RequestBody User user,                         @RequestParam("status") Integer status,                         @PathVariable("type") String type) {        return "requestBody:" + user.toString() + ",requestParam:" + status + ",      pathVariable:" + type + "";    }

客户端测试代码

    @Test    void post03(){        String uri =   BASE_URI + "/test/post02/788787/?status={1}";        User user = User.builder().id("6666").password("7777").build();        HttpHeaders httpHeaders = new HttpHeaders();        httpHeaders.setContentType(MediaType.APPLICATION_JSON);        HttpEntity<User> httpEntity = new HttpEntity<>(user,httpHeaders);        String result = restTemplate.postForObject(uri,httpEntity,String.class,0);        log.info("{}",result);    }

小结

在Web利用中咱们须要对其余服务进行HTTP调用。WebClient和RestTemplate是两个由Spring提供的客户端工具。

今日份分享已完结,请大家多多包涵和指导!