RestTemplate이란?
- 스프링에서 HTTP 통신 기능을 손쉽게 사용하도록 설계된 템플릿
- 기본적으로 동기 방식을 처리
- RESTful 원칙
-> RESTful원칙을 지키면서 외부 API를 사용할 수 있게 해주는 도구.
두 개의 프로젝트 서버포트를 다르게 해서 가동.
port1 : 9090 -> 데이터를 가져올 수 있는 외부 API
port2 : 8080 -> RestTemplate을 사용하여 8080의 데이터를 Get
먼저 port1의 Dto와 Controller
Port1 - MemberDto
@Getter
@Setter
@ToString
public class MemberDto {
private String name;
private String email;
private String organization;
}
Port1 - CrudController
@RestController
@RequestMapping("/api/v1/crud-api")
public class CrudController {
@GetMapping
public String getName() {
return "Flature";
}
@GetMapping("/{variable}")
public String getVariable(@PathVariable String variable) {
return variable;
}
@GetMapping("/param")
public String getNameWithParam(@RequestParam String name) {
return "Hello. " + name + "!";
}
}
이제 port2에서 RestTemplate을 사용하여 port1의 데이터를 가져올 것임.
Port2 - RestTemplateService
@Service
public class RestTemplateService {
public String getName() {
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")//호출하고자 하는 URL 입력
.path("/api/v1/crud-api")// 세부경로 입력
.encode()//기본 UTF-8
.build()//빌더 생성 종료
.toUri();//URI 타입으로 리턴
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
//getForEntity - GET형식으로 요청한 결과를 ResponseEntity 형식으로 반환.
return responseEntity.getBody();
}
public String getNameWithPathVariable() {
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api/{name}")
.encode()
.build()
.expand("James")//복수의 값을 넣어야할 경우 , 를 추가하여 구분
.toUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
return responseEntity.getBody();
}
public String getNameWithParameter() {
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api/param")
.queryParam("name", "Flature")
.encode()
.build()
.toUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
return responseEntity.getBody();
}
}
Port2 - RestTemplateController
@RestController
@RequestMapping("/rest-template")
public class RestTemplateController {
private final RestTemplateService restTemplateService;
public RestTemplateController(RestTemplateService restTemplateService) {
this.restTemplateService = restTemplateService;
}
@GetMapping
public String getName() {
return restTemplateService.getName();
}
@GetMapping("/path-variable")
public String getNameWithPathVariable() {
return restTemplateService.getNameWithPathVariable();
}
@GetMapping("/parameter")
public String getNameWithParameter() {
return restTemplateService.getNameWithParameter();
}
}
Port2의 결과.
getName()

getNameWithPathVariable()

getNameWithParameter()

그렇다면 RestTemplate을 사용했을 때의 문제점은 뭐가 있을까.
- 동기적인 호출
RestTemplate은 기본적으로 동기적인 호출을 수행. 즉, 요청을 보낸 후 응답이 올 때까지 블로킹되어 다른 작업을 수행할 수 없음. 이는 고가용성과 확장성이 요구되는 시스템에서 문제가 될 수 있음. - 쓰레드 블로킹
RestTemplate은 내부적으로 Java의 HttpURLConnection 또는 Apache HttpClient와 같은 블로킹 I/O를 사용하여 HTTP 요청을 처리. 이는 요청당 쓰레드를 할당하는 방식으로 동작하므로, 많은 요청을 동시에 처리해야 할 경우 쓰레드 풀을 적절히 관리하지 않으면 쓰레드 블로킹과 리소스 낭비가 발생할 수 있음. - 유지보수 및 업그레이드 어려움
RestTemplate은 스프링 프레임워크의 일부로 제공되며, 새로운 기능이나 업데이트에 대한 지원이 제한될 수 있음.
스프링 5부터는 WebClient가 권장되는 비동기 HTTP 클라이언트로 소개.
따라서, RestTemplate을 사용하는 애플리케이션을 WebClient로 마이그레이션하는 작업이 필요할 수 있습니다.
※ 블로킹이란?
- 블로킹I/O 및 동기I/O
블로킹 I/O(혹은 동기 I/O)는 I/O 작업 시 대상 파일의 디스크립터가 준비되어 있지 않은 프로세스는 시스템 호출 응답 대기상태(차단 상태)가 된다.
즉, 그 동안 프로그램 처리를 진행할 수 없음. - 논-블로킹 I/O와 비동기 I/O 차이
논-블로킹 I/O는 처리가 완료되지 않으면 에러를 회신하고, 블록 상태로 만들지 않는 반면 비동기 I/O는 처리를 바로할 수 없을 때. 처리가 완료 되는 시점가지 백그라운드에서 대기하고, 종료한 타이밍을 회신 하는 차이가 있다.