Search code examples
spring-integrationwebclientspring-webclient

How to use webClient in Spring Integration?


I'm trying to use webClient in my Spring Integration application. Using block() method i got this error:

org.springframework.messaging.MessageHandlingException: error occurred during processing message in 'MethodInvokingMessageProcessor' [org.springframework.integration.handler.MethodInvokingMessageProcessor@28b67bb]; nested exception is java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-4
    at org.springframework.integration.support.utils.IntegrationUtils.wrapInHandlingExceptionIfNecessary(IntegrationUtils.java:192) ~[spring-integration-core-5.4.5.jar:5.4.5]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:

So I removed the block to prevent the issue but I looks like the calling is not executing without that. I don't know how make it work

Activator

@ServiceActivator(
    inputChannel = "lisContractValidationChannel",
    outputChannel = "aopContractValidationReplyAndContinueRouterChannel"

)
public Application sendEContract(Application application) {
    
    ContractRequest contractRequest = prepareRequest(application);
    
    lisOperations.verifyContract(contractRequest,
        application.getContractData().getRouteOne().getConversationID(),
        application.getRouteOneId());
    
    return application;
}

Operations

private final WebClient webClient;

@Override
public void verifyContract(
    EContractRequest contractRequest,
    String vendorTransactionId,
    String loanId) {

    
    webClient.post()
        .uri(baseUrl + contract)
        .header("sourceRequestId", sourceRequestId)
        .header("VENDOR-ID", String.join(";", List.of(vendorId, vendorTransactionId, loanId)))
        .bodyValue(contractRequest).retrieve().toEntity(LisResponse.class);
} 

WebClient Configuration

@Bean
public WebClient webClient(MetricsDTWebClientFilterFunction metricsDTWebClientFilterFunction) {
    
    HttpClient httpClient = HttpClient
        .create();
    
    final WebClient.Builder webClientBuilder = WebClient.builder()
        .clientConnector(new ReactorClientHttpConnector(httpClient))
        .codecs(ClientCodecConfigurer::defaultCodecs)
        .filter(metricsDTWebClientFilterFunction);
    
    return webClientBuilder.build();
}

Solution

  • The webClient is reactive component and any Reactive Streams solution requires a subscription for their execution. And what is more important it is recommended to do them non-blocking way. That's why you got such a Block Hound error for using that block() operator.

    Since toEntity() returns a Mono for us you simply can use its subscribe() to initiate a request execution. It may exit immediately from your verifyContract() though just because an execution may happen on a different thread.

    This way you may consider to change a contract of your verifyContract() to a Mono to propagate it downstream for subscription in their calls.

    Please, learn more about Project Reactor to make yourself familiar with all of this blocking and non-blocking stuff: https://projectreactor.io/