亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何使用 WebClient 而不是 RestTemplate 來執行非阻塞和異步調用

如何使用 WebClient 而不是 RestTemplate 來執行非阻塞和異步調用

動漫人物 2023-05-17 14:28:16
我有一個使用 Springboot Resttemplate 的 springboot 項目。我們已經從 1.5.3 遷移到 springboot 2.0.1,我們正試圖通過使用 WebClient 使它的其余調用異步。我們曾經使用 Resttemplate 處理接收到的字符串,如下所示。但 WebClient 僅返回 Mono 或 Flux 中的數據。如何獲取字符串形式的數據。已經嘗試過 block() 方法,但它執行異步調用。@Retryable(maxAttempts = 4, value = java.net.ConnectException.class,           backoff = @Backoff(delay = 3000, multiplier = 2))public Mono<String> getResponse(String url) {    return webClient.get().uri(urlForCurrent).accept(APPLICATION_JSON)                    .retrieve()                    .bodyToMono(String.class);}使用 RestTemplate 呈現數據流控制器接收客戶端調用provider 獲取 String 格式的數據提供程序處理字符串數據被提供給控制器Controller.java@RequestMapping(value = traffic/, method = RequestMethod.GET,                produces = MediaType.APPLICATION_JSON_VALUE)public String getTraffic(@RequestParam("place") String location) throws InterruptedException, ExecutionException {    String trafficJSON = Provider.getTrafficJSON(location)    return trafficJSON;}Provider.javapublic String getTrafficJSON(String location) {    String url = ----;    ResponseEntity<String> response = dataFetcher.getResponse(url);    /// RESPONSEBODY IS READ AS STRING AND IT NEEDS TO BE PROCESSED    if (null != response {        return parser.transformJSON(response.getBody(), params);    }    return null;}DataFetcher.java@Retryable(maxAttempts = 4,           value = java.net.ConnectException.class,           backoff = @Backoff(delay = 3000, multiplier = 2))public ResponseEntity<String> getResponse(String url) {    /* ----------------------- */    return getRestTemplate().getForEntity(urlForCurrent, String.class);}
查看完整描述

3 回答

?
胡說叔叔

TA貢獻1804條經驗 獲得超8個贊

由于存在很多誤解,所以在這里我要澄清一些事情。

Spring 已經正式聲明,如果可以的話,如果你想盡可能地證明未來,請使用RestTemplate它。maintenence modeWebClient

如RestTemplate API中所述

注意:從 5.0 開始,這個類處于維護模式,只有少量的更改請求和錯誤被接受。請考慮使用org.springframework.web.reactive.client.WebClient具有更現代 API 并支持同步、異步和流式傳輸方案的 。

非反應性應用

如果您的應用程序是非反應性應用程序(不向調用客戶端返回通量或單聲道),您必須做的是block()在需要該值時使用。您當然可以在您的應用程序內部使用Monoor?Flux,但最后您必須調用block()以獲取返回給調用客戶端所需的具體值。

非反應性應用程序使用例如作為底層服務器實現,它遵循 servlet 規范,因此它將為每個請求分配 1 個線程,因此您將無法獲得反應性應用程序所獲得的性能提升tomcatundertow

響應式應用

另一方面,如果您有一個反應性應用程序,則在任何情況下都不應調用block()您的應用程序。阻塞正是它所說的,它會阻塞一個線程并阻止該線程執行直到它可以繼續,這在反應世界中是不好的。

您也不應該調用subscribe您的應用程序,除非您的應用程序是響應的最終消費者。例如,如果您正在調用一個 api 來獲取數據并寫入您的應用程序連接到的數據庫。您的后端應用程序是最終消費者。如果外部客戶端正在調用您的后端(例如反應、角度應用程序、移動客戶端等),則外部客戶端是最終消費者,并且是訂閱者。不是你。

這里的底層默認服務器實現是一個netty服務器,它是一個非 servlet、基于事件的服務器,不會每個請求分配一個線程,服務器本身是線程不可知的,任何可用的線程都將在任何請求期間隨時處理任何事情。

webflux文檔清楚地指出,servlet 3.1+ 支持的服務器 tomcat 和 jetty 都可以與 webflux 以及非 serlet 服務器 netty 和 undertow 一起使用。

我怎么知道我有什么應用程序?

Spring 指出,如果您同時擁有spring-webspring-webflux在類路徑中,則應用程序將支持spring-web并默認啟動具有底層 tomcat 服務器的非反應性應用程序。

如果需要作為彈簧狀態,可以手動覆蓋此行為。

在您的應用程序中同時添加spring-boot-starter-webspring-boot-starter-webflux模塊會導致 Spring Boot 自動配置 Spring MVC,而不是 WebFlux。選擇此行為是因為許多 Spring 開發人員將其添加spring-boot-starter-webflux到他們的 Spring MVC 應用程序中以使用反應式 WebClient。您仍然可以通過將所選應用程序類型設置為 來強制執行您的選擇SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE)。

“Spring WebFlux 框架”

那么如何按照題目提供的代碼實現WebClient呢?

@Retryable(maxAttempts = 4,

? ? ? ?value = java.net.ConnectException.class,

? ? ? ?backoff = @Backoff(delay = 3000, multiplier = 2))

public Mono<String> getResponse(String url) {

? ? return webClient.get()

? ? ? ? ? ? .uri(url)

? ? ? ? ? ? .exchange()

? ? ? ? ? ? .flatMap(response -> response.toEntity(String.class));

}

我會說這是最簡單和最少侵入性的實現。您當然需要構建一個合適的網絡客戶端,@Bean并將其自動連接到它的類中。


查看完整回答
反對 回復 2023-05-17
?
MYYA

TA貢獻1868條經驗 獲得超4個贊

第一步是WebClient使用 baseUrl 構建對象;

WebClient webClient = WebClient.builder()
    .baseUrl("http://localhost:8080/api") //baseUrl
    .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
    .build();

然后選擇方法并將路徑與請求變量或正文有效負載一起附加。

ResponseSpec responseSpec = webClient
    .get()
    .uri(uriBuilder -> uriBuilder.path("/findById") //additional path
        .queryParam("id", id).build())
    .retrieve()
    .onStatus(HttpStatus::is4xxClientError, response -> Mono.error(new CustomRuntimeException("Error")));

等待響應的block()功能bodyToMono。如果你想要響應作為字符串,你可以使用谷歌的 gson 庫來轉換它。

Object response = responseSpec.bodyToMono(Object.class).block();Gson gson = new Gson();String str = gson.toJson(response);

如果你不想知道 api 調用的狀態,你可以像下面那樣做。

webClient
    .post()
    .uri(uri -> uri.path("/save").build())
    .body( BodyInserters.fromObject(payload) )
    .exchange().subscribe();


查看完整回答
反對 回復 2023-05-17
?
繁星點點滴滴

TA貢獻1803條經驗 獲得超3個贊

首先要了解的是,如果您需要調用,.block()不妨堅持使用RestTemplate,使用 WebClient 將一無所獲。


如果你想從使用 WebClient 中獲益,你需要開始以反應的方式思考。反應過程實際上只是一系列步驟,每個步驟的輸入都是前一步的輸出。當收到請求時,您的代碼會創建步驟序列并立即返回并釋放 http 線程。當上一步的輸入可用時,框架然后使用工作線程池來執行每個步驟。


這樣做的好處是在接受競爭請求的能力上獲得了巨大的收益,而代價很小,而不得不重新考慮您編寫代碼的方式。您的應用程序只需要一個非常小的 http 線程池和另一個非常小的工作線程池。


當您的控制器方法返回Monoor時Flux,您就做對了,不需要調用block().


像這樣的最簡單的形式:


@GetMapping(value = "endpoint", produces = MediaType.TEXT_PLAIN_VALUE)

@ResponseBody

@ResponseStatus(OK)

public Mono<String> controllerMethod() {


    final UriComponentsBuilder builder =

            UriComponentsBuilder.fromHttpUrl("http://base.url/" + "endpoint")

                    .queryParam("param1", "value");


    return webClient

            .get()

            .uri(builder.build().encode().toUri())

            .accept(APPLICATION_JSON_UTF8)

            .retrieve()

            .bodyToMono(String.class)

            .retry(4)

            .doOnError(e -> LOG.error("Boom!", e))

            .map(s -> {


                // This is your transformation step. 

                // Map is synchronous so will run in the thread that processed the response. 

                // Alternatively use flatMap (asynchronous) if the step will be long running. 

                // For example, if it needs to make a call out to the database to do the transformation.


                return s.toLowerCase();

            });

}

轉向反應式思考是一個相當大的范式轉變,但值得付出努力。堅持住,一旦您能夠在整個應用程序中完全沒有阻塞代碼,這真的不是那么困難。構建步驟并返回它們。然后讓框架管理步驟的執行。


如果有任何不清楚的地方,我們很樂意提供更多指導。


記得玩得開心:)


查看完整回答
反對 回復 2023-05-17
  • 3 回答
  • 0 關注
  • 249 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號