복붙노트

[SPRING] 전통적인 서블릿 다중 스레드 응용 프로그램에서 봄 부팅 WebClient.Builder 콩 사용

SPRING

전통적인 서블릿 다중 스레드 응용 프로그램에서 봄 부팅 WebClient.Builder 콩 사용

나는 스프링 클라이언트에서 다른 마이크로 서비스를 호출 할 수있는 HTTP 클라이언트를 가지고 싶습니다. RestTemplate이 사용되지 않으므로 WebClient.Builder 및 WebClient를 사용하려고했습니다. 스레드의 안전성에 대해서는 확신하지 못합니다. 여기 예 :

@Service
public class MyService{
    @Autowired
    WebClient.Builder webClientBuilder;

    public VenueDTO serviceMethod(){
        //!!! This is not thread safe !!!
        WebClient webClient = webClientBuilder.baseUrl("http://localhost:8000").build();

        VenueDTO venueDTO = webClient.get().uri("/api/venue/{id}", bodDTO.getBusinessOutletId()).
                retrieve().bodyToMono(VenueDTO.class).
                blockOptional(Duration.ofMillis(1000)).
                orElseThrow(() -> new BadRequestException(venueNotFound));
                return VenueDTO;
    }
}

이 예제의 serviceMethod ()는 몇 개의 스레드에서 호출되며 webClientBuilder는 단일 Bean 인스턴스입니다. WebClient.Builder 클래스에는 state : baseUrl이 포함되어 있으며이 상태 업데이트를 동시에 호출 할 수있는 스레드가 거의 없으므로 스레드로부터 안전하지 않은 것으로 보입니다. 그 사이에 WebClient 자체가 스레드 안전합니다 답변을 스프링에서 WebClient를 멀티 스레드 환경에서 사용하는 올바른 방법

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-webclient.html에서 언급 한 WebClient.Builder 빈을 사용해야합니까?

내가 보게되는 해결 방법 중 하나는 빌더에 전달 된 상태를 사용하지 않고 WebClient를 작성하는 것입니다.

WebClient webClient = webClientBuilder.baseUrl("http://localhost:8000").build();

내가 할 것이다:

WebClient webClient = webClientBuilder.build();

uri 메소드 호출에서 프로토콜과 포트로 전체 url을 전달하십시오.

webClient.get().uri("full url here", MyDTO.class)

내 경우에 그것을 사용하는 적절한 방법은 무엇입니까?

해결법

  1. ==============================

    1.맞습니다. WebClient.Builder는 스레드로부터 안전하지 않습니다.

    맞습니다. WebClient.Builder는 스레드로부터 안전하지 않습니다.

    스프링 부트는 WebClient.Builder를 프로토 타입 빈으로 생성하므로 각 주입 지점에 대해 새로운 인스턴스를 얻습니다. 귀하의 경우 귀하의 구성 요소가 제 생각에 약간 이상하게 보입니다.

    오히려 다음과 같이 보일 것입니다.

    @Service
    public class MyService{
    
        private final WebClient webClient;
    
        public MyService(WebClient.Builder webClientBuilder) {
            this.webClient = webClientBuilder.baseUrl("http://localhost:8000").build();
        }
    
        public VenueDTO serviceMethod(){
            VenueDTO venueDTO = webClient.get().uri("/api/venue/{id}", bodDTO.getBusinessOutletId()).
                    retrieve().bodyToMono(VenueDTO.class).
                    blockOptional(Duration.ofMillis(1000)).
                    orElseThrow(() -> new BadRequestException(venueNotFound));
                    return VenueDTO;
        }
    }
    

    이제 이것이 코드 스 니펫이고 응용 프로그램에 다른 제약이있을 수 있습니다.

    애플리케이션이 기본 URL을 자주 변경해야하는 경우 빌더에서 구성을 중지하고 질문에 언급 된 전체 URL을 전달해야한다고 생각합니다. 응용 프로그램에 다른 요구 사항 (인증 등에 대한 사용자 정의 헤더 등)이있는 경우 빌더에서 또는 요청별로이를 수행 할 수 있습니다.

    일반적으로 구성 요소마다 단일 WebClient 인스턴스를 만들어야합니다. 각 요청에 대해 다시 작성하는 것은 매우 낭비입니다.

    응용 프로그램에 매우 특정한 제약 조건이있어 실제로 다른 인스턴스를 만들어야하는 경우에는 항상 webClientBuilder.clone ()을 호출하고 스레드 안전성 문제없이 변경할 수있는 빌더의 새 인스턴스를 가져올 수 있습니다.

  2. from https://stackoverflow.com/questions/54136085/spring-boot-webclient-builder-bean-usage-in-traditional-servlet-multi-threaded-a by cc-by-sa and MIT license