๐ŸŒ€
f1v3-log
  • Welcome
  • ๊ฐœ๋ฐœ
    • SecurityContext๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์•ผ ํ• ๊นŒ?
    • OAuth2AuthorizationRequestResolver ์ปค์Šคํ„ฐ๋งˆ์ด์ง•
    • ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ณด์ž
    • MySQL์€ ์–ด๋–ป๊ฒŒ ID ๊ฐ’์„ ์ˆœ์ฐจ์ ์œผ๋กœ ๋„ฃ์–ด์ฃผ๋Š” ๊ฒƒ์ผ๊นŒ? (Feat. Auto Increment Lock)
    • ์™ธ๋ถ€ API ํ˜ธ์ถœ์— ๋Œ€ํ•œ ๊ณ ์ฐฐ
      • HTTP Clients in Spring Boot
      • I/O์™€ ํŠธ๋žœ์žญ์…˜ ๋ถ„๋ฆฌํ•˜๊ธฐ
      • ์ฒ˜๋ฆฌ์œจ ์ œํ•œ ์žฅ์น˜ (Rate Limiter) ๋„์ž…
      • ์™ธ๋ถ€ API ์˜์กด์„ฑ์„ ์ค„์—ฌ๋ณด์ž
      • ์บ์‹œ ๋ ˆ์ด์–ด๋ฅผ ๊ตฌ์„ฑํ•ด๋ณด์ž (Local Cache)
    • JPA Deep Dive
      • ๊ฒฐ์ œ ๋ฐ ์ •์‚ฐ ์‹œ์Šคํ…œ ๊ธฐ๋Šฅ ์š”๊ตฌ์‚ฌํ•ญ ๋ถ„์„
      • ๊ธ€๋กœ๋ฒŒ ์„œ๋น„์Šค๋ฅผ ๊ณ ๋ คํ•  ๋•Œ, ํƒ€์ž„์กด ์ด์Šˆ๋ฅผ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ• ๊นŒ?
      • Spring Data JPA - ID ์ƒ์„ฑ ์ „๋žต๊ณผ ์ฑ„๋ฒˆ์€ ์–ด๋–ป๊ฒŒ ๋˜๋Š”๊ฑธ๊นŒ?
  • ํšŒ๊ณ 
    • NHN Academy ์ธ์ฆ๊ณผ์ • ํšŒ๊ณ 
    • DND 11๊ธฐ ํšŒ๊ณ 
  • ๋…์„œ
    • Effective Java 3/E
      • Item 1. ์ƒ์„ฑ์ž ๋Œ€์‹  ์ •์  ํŒฉํ„ฐ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ๊ณ ๋ คํ•˜๋ผ
      • Item 2. ์ƒ์„ฑ์ž์— ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋งŽ๋‹ค๋ฉด ๋นŒ๋”๋ฅผ ๊ณ ๋ คํ•˜๋ผ
      • Item 3. private ์ƒ์„ฑ์ž๋‚˜ ์—ด๊ฑฐ ํƒ€์ž…์œผ๋กœ ์‹ฑ๊ธ€ํ„ด์ž„์„ ๋ณด์ฆํ•˜๋ผ
    • ๊ฐ์ฒด์ง€ํ–ฅ์˜ ์‚ฌ์‹ค๊ณผ ์˜คํ•ด
      • 1์žฅ. ํ˜‘๋ ฅํ•˜๋Š” ๊ฐ์ฒด๋“ค์˜ ๊ณต๋™์ฒด
      • 2์žฅ. ์ด์ƒํ•œ ๋‚˜๋ผ์˜ ๊ฐ์ฒด
      • 3์žฅ. ํƒ€์ž…๊ณผ ์ถ”์ƒํ™”
      • 4์žฅ. ์—ญํ• , ์ฑ…์ž„, ํ˜‘๋ ฅ
      • 5์žฅ. ์ฑ…์ž„๊ณผ ๋ฉ”์‹œ์ง€
      • 6์žฅ. ๊ฐ์ฒด ์ง€๋„
      • 7์žฅ. ํ•จ๊ป˜ ๋ชจ์œผ๊ธฐ
  • Real MySQL 8.0
    • 04. ์•„ํ‚คํ…์ฒ˜
    • 05. ํŠธ๋žœ์žญ์…˜๊ณผ ์ž ๊ธˆ
    • 08. ์ธ๋ฑ์Šค
    • 09. ์˜ตํ‹ฐ๋งˆ์ด์ €์™€ ํžŒํŠธ
  • ์ƒ๊ฐ์ •๋ฆฌ
    • ๊ธฐ์ˆ ์— ๋งค๋ชฐ๋˜์ง€ ๋ง์ž.
  • ๊ณต๋ถ€
    • ๊ฐ์ฒด์ง€ํ–ฅ 5์›์น™(SOLID)
      • SRP (Single Responsibility Principle)
      • OCP (Open Closed Principle)
Powered by GitBook
On this page
  • 1. RestTemplate
  • 2. WebClient
  • 3. OpenFeign (FeignClient)
  • ์ฝ์–ด๋ณผ๊ฑฐ๋ฆฌ

Was this helpful?

  1. ๊ฐœ๋ฐœ
  2. ์™ธ๋ถ€ API ํ˜ธ์ถœ์— ๋Œ€ํ•œ ๊ณ ์ฐฐ

HTTP Clients in Spring Boot

Previous์™ธ๋ถ€ API ํ˜ธ์ถœ์— ๋Œ€ํ•œ ๊ณ ์ฐฐNextI/O์™€ ํŠธ๋žœ์žญ์…˜ ๋ถ„๋ฆฌํ•˜๊ธฐ

Last updated 4 months ago

Was this helpful?

๋จผ์ €, ์Šคํ”„๋ง์—์„œ ์™ธ๋ถ€ API๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ํ•˜๋‚˜์”ฉ ์•Œ์•„๋ณด์ž.

Java ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ HttpURLConnection ์€ ๋„˜์–ด๊ฐ€์ž.

๊ธฐ๋ณธ์ ์ธ ์š”์ฒญ/์‘๋‹ต ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์ง€๋งŒ, ์‘๋‹ต ์ฒ˜๋ฆฌ๊ฐ€ ๋ณต์žกํ•˜๋ฉฐ ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์ด ๋‚ฎ๋‹ค๋Š” ๋‹จ์ ์œผ๋กœ ์ž˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

1. RestTemplate

๋งŒ์•ฝ RestTemplate์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋ผ๋ฉด ์•„๋ž˜์˜ ๊ธ€์˜ ์ฃผ์˜์‚ฌํ•ญ์„ ์ฐธ๊ณ ํ•˜์ž.

๋Œ€ํ‘œ์ ์ธ Spring์˜ HTTP Client ์ค‘ ํ•˜๋‚˜์ด์ง€๋งŒ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋Œ€์•ˆ์„ ๊ถŒ์žฅํ•˜๊ณ  ์žˆ๋‹ค.

  • ๋™๊ธฐ์‹ ์š”์ฒญ: RestClient

  • ๋น„๋™๊ธฐ/์ŠคํŠธ๋ฆฌ๋ฐ: WebClient

์ฃผ์š” ํŠน์ง•

  • ์˜ค๋žซ๋™์•ˆ Spring ์ง„์˜์—์„œ ์ง€์›๋˜๊ณ  ์žˆ์Œ

  • ๋™๊ธฐ์‹ Blocking ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘

  • RESTful ์›์น™ ์ค€์ˆ˜

๊ธฐ๋ณธ์ ์ธ ์‚ฌ์šฉ๋ฒ•

Bean ๋“ฑ๋ก

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

์š”์ฒญ ์˜ˆ์‹œ

@Service
public class ExampleService {
    private final RestTemplate restTemplate;
    
    public String getData() {
        return restTemplate.getForObject(
            "http://example.com/api",
            String.class
        );
    }
}

RestTemplate์„ ์‚ฌ์šฉํ•˜์—ฌ ์™ธ๋ถ€ API๋ฅผ ํ˜ธ์ถœํ•ด์•ผํ•˜๋Š” ์ƒํ™ฉ์ผ ๊ฒฝ์šฐ ํƒ€์ž„์•„์›ƒ(Timeout), ์žฌ์‹œ๋„(retry), ๋กœ๊น…(Logging), ์„œํ‚ท ๋ธŒ๋ ˆ์ด์ปค ๋“ฑ์„ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋‘๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

2. WebClient

Spring WebFlux์— ํฌํ•จ๋œ HTTP ํด๋ผ์ด์–ธํŠธ๋กœ, Non-Blocking I/O๋ฅผ ํ™œ์šฉํ•œ ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ชจ๋ธ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ๋‹ค.

์ฃผ์š” ํŠน์ง•

  • ๋น„๋™๊ธฐ/Non-Blocking ๋ฐฉ์‹ ์ง€์›

  • ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘

  • Reactor ๊ธฐ๋ฐ˜์˜ ์„ ์–ธ์  API ์ œ๊ณต

Reactor: JVM ์œ„์—์„œ ๋™์ž‘ํ•˜๋Š” ๋…ผ๋ธ”๋กœํ‚น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ๋ฆฌ์•กํ‹ฐ๋ธŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

๊ธฐ๋ณธ์ ์ธ ์‚ฌ์šฉ๋ฒ•

Bean ๋“ฑ๋ก

@Configuration
public class WebClientConfig {
    @Bean
    public WebClient webClient() {
        return WebClient.builder()
            .baseUrl("http://api.example.com")
            .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
            .build();
    }
}

์š”์ฒญ ์˜ˆ์‹œ

@Service
public class ExampleService {
    private final WebClient webClient;
    
    public Mono<UserResponse> getUser(String userId) {
        return webClient.get()
            .uri("/users/{id}", userId)
            .retrieve()
            .bodyToMono(UserResponse.class);
    }
}

๋งŒ์•ฝ ํ•™์Šต์ด ํ•„์š”ํ•˜๋‹ค๋ฉด ์•„๋ž˜์˜ ๊ณต์‹ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ํ•œ๊ธ€๋กœ ๋ฒˆ์—ญํ•œ ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

3. OpenFeign (FeignClient)

Spring Cloud OpenFeign์€ Netflix์—์„œ ๊ฐœ๋ฐœํ•œ ์„ ์–ธ์  REST ํด๋ผ์ด์–ธํŠธ๋กœ, org.springframework.cloud ํŒจํ‚ค์ง€์— ํฌํ•จ์ด ๋˜์–ด์žˆ๋‹ค.

์ฃผ์š” ํŠน์ง•

  • ์„ ์–ธ์  REST Client - ์ธํ„ฐํŽ˜์ด์Šค + ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ๊ตฌํ˜„ ๊ฐ€๋Šฅ

  • ๋™๊ธฐ์‹ HTTP ํ†ต์‹  ๋ฐฉ์‹ (๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋„ ๊ฐ€๋Šฅ)

๊ธฐ๋ณธ์ ์ธ ์‚ฌ์šฉ๋ฒ•

@FeignClient(name = "book-service", url = "${api.book.url}")
public interface BookClient {
    @GetMapping("/api/books")
    List<Book> searchBooks(
        @RequestParam String query,
        @RequestHeader(HttpHeaders.AUTHORIZATION) String authorization
    );
}

์œ„์ฒ˜๋Ÿผ Spring MVC์˜ ์–ด๋…ธํ…Œ์ด์…˜ ๋ฐฉ์‹์œผ๋กœ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๋งŒ์•ฝ, RestTemplate ์„ ์‚ฌ์šฉํ•œ๋‹ค ํ–ˆ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ ๊ตฌ์กฐ๋กœ ํ˜ธ์ถœ์„ ํ•ด์•ผํ•œ๋‹ค.

@Component
@RequiredArgsConstructor
public class BookRestTemplate {

    private final RestTemplate restTemplate;
    private final String apiUrl;
    private final String apiKey;

    public List<Book> search(String query) {
        String url = createSearchUrl(query);
        HttpHeaders headers = createHeaders();
        
        HttpEntity<?> entity = new HttpEntity<>(headers);
        
        ResponseEntity<List<Book>> response = restTemplate.exchange(
            url,
            HttpMethod.GET,
            entity,
            new ParameterizedTypeReference<List<Book>>() {}
        );
        return response.getBody();
    }

    private String createSearchUrl(String query) {
        return UriComponentsBuilder.fromUriString(apiUrl)
            .path("/api/books")
            .queryParam("query", query)
            .encode()
            .build()
            .toUriString();
    }

    private HttpHeaders createHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.set(HttpHeaders.AUTHORIZATION, "KEY " + apiKey);
        return headers;
    }
}

ํŠน์ง•

  1. ์ง๊ด€์ ์ธ ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜์œผ๋กœ ์„ค๊ณ„๊ฐ€ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ์ฝ”๋“œ๊ฐ€ ์ตœ์†Œํ™” ๋ฉ๋‹ˆ๋‹ค.

  2. ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ ์ธก๋ฉด์—์„œ๋„ ๋›ฐ์–ด๋‚˜๋‹ค.

  3. ํ™•์žฅ์„ฑ์„ ๊ณ ๋ คํ–ˆ์„ ๋•Œ Retry, Circuit Breaker ๋“ฑ์„ ๋„์ž…ํ•˜๊ธฐ ํŽธํ•˜๋‹ค.

ํ•˜์ง€๋งŒ, ์–ด๋…ธํ…Œ์ด์…˜๊ณผ ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜์œผ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•ด์•ผํ•˜์ง€๋งŒ ํ…Œ์ŠคํŠธ ๋„๊ตฌ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋‹จ์ ์ด ์กด์žฌํ•œ๋‹ค.

์ฝ์–ด๋ณผ๊ฑฐ๋ฆฌ

image

[Spring] RestTemplate ํƒ€์ž„์•„์›ƒ(Timeout), ์žฌ์‹œ๋„(Retry), ๋กœ๊น…(Logging) ๋“ฑ ์„ค์ •ํ•˜๊ธฐ
[Spring] RestTemplate์—
Resilence4J ์„œํ‚ท ๋ธŒ๋ ˆ์ด์ปค ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ์˜ˆ์‹œ
https://incheol-jung.gitbook.io/docs/q-and-a/spring/resttemplate
REST Clients :: Spring Framework
Logo
WebClient :: Spring Framework
Logo
Spring WebFlux (1)Dain Lee
Spring Cloud OpenFeign
Logo
feign ์ข€๋” ๋‚˜์•„๊ฐ€๊ธฐ | ์šฐ์•„ํ•œํ˜•์ œ๋“ค ๊ธฐ์ˆ ๋ธ”๋กœ๊ทธ์šฐ์•„ํ•œํ˜•์ œ๋“ค ๊ธฐ์ˆ ๋ธ”๋กœ๊ทธ |
Logo
Feign ์ฝ”๋“œ ๋ถ„์„๊ณผ ์„œ๋ฒ„ ์„ฑ๋Šฅ ๊ฐœ์„ Toss_service
Logo
Logo