MicroService Communication
Communication Types
동기 방식으로 통신하는 경우 HTTP 통신을 사용할 수 있다. 이 방식을 사용하면 요청을 보냈을 때 응답이 올 때 까지 기다려야 하므로 그동안 다른 작업을 수행할 수 없다.
비동기 방식으로는 AMQP 를 사용할 수 있다.
RestTemplate
REST API 요청을 위해 스프링 프레임워크에서 제공하는 클래스이다.
사용 방법
보통은 하나의 RestTemplate 객체를 만들어 각 서비스마다 빈으로 주입해 사용한다.
@Configuration
public class Config {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@Service
public class UserService {
// 생성자 주입
private final RestTemplate restTemplate;
// ...
public UserDto getUserByUserId(String userId) {
// user 정보 조회
// ...
// order 정보 조회
String orderUrl = "http://.../order-service/.../orders";
ResponseEntity<List<ResponseOrder>> response = restTemplate.exchange(orderUrl, HttpMethod.GET, null,
new ParameterizedTypeReference<List<ResponseOrder>>() {});
List<ResponseOrder> orders = response.getBody();
userDto.setOrders(orders);
return userDto;
}
}
FeignClient
REST 호출을 추상화한 Spring Cloud Netflix 라이브러리이다.
호출하려는 HTTP Endpoint에 대한 인터페이스를 생성하고 @FeignClient 어노테이션을 추가해 사용할 수 있다.
로드밸런싱 기능을 제공한다.
사용 방법
의존성을 추가하고 @EnableFeignClients 어노테이션을 설정 클래스에 추가한다.
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
@EnableFeignClients
public class Config {
}
인터페이스를 생성한다. @FeignClient 어노테이션의 name 속성에는 API 호출 대상인 마이크로 서비스의 이름을 입력한다. 인터페이스 메서드는 Controller와 동일한 형태로 작성하면 된다.
@FeignClient(name=order-service)
public interface OrderServiceClient {
@GetMapping("/order-service/{userId}/orders")
List<ResponseOrder> getOrders(@PathVariable String userId);
}
서비스 클래스에서는 인터페이스를 빈으로 입력받아 사용할 수 있다.
@Service
public class UserService {
// 생성자 주입
private final OrderServiceClient orderServiceClient;
// ...
public UserDto getUserByUserId(String userId) {
// user 정보 조회
// ...
// order 정보 조회
List<ResponseOrder> orders = orderServiceClient.getOrders(userId);
userDto.setOrders(orders);
return userDto;
}
}
예외 처리
FeignClient 사용 중에 만약 http uri가 잘못되었다면 FeignException이 발생할 것이다.
try-catch로 예외를 처리할 수도 있지만 ErrorDecoder를 이용해 예외를 집약적으로 처리할 수 있다.
사용 방법
Errordecoder 클래스를 생성해 각 예외 원인마다 원하는 예외 처리를 해주고 이 클래스를 빈으로 등록해주면 된다.
public class FeignErrorDecoder implements ErrorDecoder {
@Override
public Exception decode(String methodKey, Response response) {
switch (response.status()) {
case 400:
break;
case 404:
if (methodKey.contains("getOrders")) {
return new ResponseStatusException(HttpStatus.valueOf(response.status()), "User's order is empty");
}
break;
default:
return new Exception(response.reason());
}
}
}
@Configuration
public class Config {
@Bean
public FeignErrorDecoder feignErrorDecoder() {
return new FeignErrorDecoder();
}
}
Last updated