source

Spring Boot Web Client.기존 서블릿 멀티스레드 애플리케이션에서 빌더빈 사용

manysource 2023. 7. 24. 22:37

Spring Boot Web Client.기존 서블릿 멀티스레드 애플리케이션에서 빌더빈 사용

저는 반응형 애플리케이션이 아닌 스프링 부트의 다른 마이크로 서비스를 호출하기 위해 http 클라이언트를 원합니다.RestTemplate가 더 이상 사용되지 않기 때문에 WebClient를 사용하려고 했습니다.작성기 및 Web Client.스레드의 안전성에 대해서는 확신할 수 없지만요.다음은 예입니다.

@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는 단일 빈 인스턴스입니다.웹 클라이언트.Builder 클래스에 state: baseUrl이 포함되어 있으며, 이 상태 업데이트를 동시에 호출할 수 있는 스레드가 거의 없기 때문에 스레드가 안전하지 않은 것 같습니다.반면 WebClient 자체는 멀티 스레드 환경에서 Spring WebClient를 사용하는 올바른 방법에 대한 답변에서 언급한 대로 스레드 안전한 것으로 보입니다.

Web Client를 사용해야 합니까?https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-webclient.html 에 언급된 빌더빈

Spring Boot은 Web Client를 생성하고 사전 구성합니다.작성자: 구성요소에 작성한 후 Web Client 인스턴스를 작성하는 데 사용하는 것이 좋습니다.

해결 방법 중 하나는 다음 대신 Web Client를 생성하는 것입니다.

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

수행할 작업:

WebClient webClient = webClientBuilder.build();

프로토콜 및 포트 inuri 메서드 호출을 사용하여 전체 URL을 전달합니다.

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

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

맞아요.WebClient.Builder스레드 세이프가 아닙니다.

Spring Boot가 생성 중입니다.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()스레드 안전 문제 없이 변형할 수 있는 새 작성기 인스턴스를 가져옵니다.

언급URL : https://stackoverflow.com/questions/54136085/spring-boot-webclient-builder-bean-usage-in-traditional-servlet-multi-threaded-a