FeignClient
- REST Call을 추상화 한 Spring Cloud Netflix 라이브러리
1. FeignClient
1). 구현
OrderServiceClient.java
@FeignClient(name = "order-service")
public interface OrderServiceClient {
// 다 퍼블릭이라서 따로 적을 필요는 없다
@GetMapping("/order-service/{userId}/orders")
List<ResponseOrder> getOrders(@PathVariable String userId);
}
UserServiceImpl.java
@Override
public UserDto getUserByUserId(String userId) {
UserEntity userEntity = userRepository.findAllByUserId(userId);
if (userEntity == null)
throw new UsernameNotFoundException("User not found");
UserDto userDto = new ModelMapper().map(userEntity, UserDto.class);
/* feing client 첫번째 사용 */
/* Feign exception handling */
List<ResponseOrder> orderList = orderServiceClient.getOrders(userId);
userDto.setOrders(orderList);
return userDto;
}
2). Feign Client에서 로그 사용
application.yml
logging:
level:
com.example.userservice.client: DEBUG
Bean 등록
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
3). Feign Client에서 예외처리
// 오타를 내보자
@GetMapping("/order-service/{userId}/orders-ng")
List<ResponseOrder> getOrders(@PathVariable String userId);
UserServiceImpl.java
@Override
public UserDto getUserByUserId(String userId) {
UserEntity userEntity = userRepository.findAllByUserId(userId);
if (userEntity == null)
throw new UsernameNotFoundException("User not found");
UserDto userDto = new ModelMapper().map(userEntity, UserDto.class);
/* feing client 첫번째 사용 */
/* Feign exception handling */
List<ResponseOrder> orderList = null;
try {
orderServiceClient.getOrders(userId);
} catch (FeignException ex) {
log.error(ex.getMessage());
}
userDto.setOrders(orderList);
return userDto;
}
4). FeignErrorDecoder
- decode는 페인 클라이언트에서 발생한 에러가 어떤 에러가 발생했는지 상태코드를 가지고 분기되어 있는 적절한 코드를 나눠서 작업할 수 있게 해준다.
Bean 등록
@Bean
public FeignErrorDecoder getFeignErrorDecoder() {
return new FeignErrorDecoder();
}
FeignErrorDecoder.java
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 orders is empty.");
}
break;
default:
return new Exception(response.reason());
}
return null;
}
}
UserServiceImpl.java
@Override
public UserDto getUserByUserId(String userId) {
UserEntity userEntity = userRepository.findAllByUserId(userId);
if (userEntity == null)
throw new UsernameNotFoundException("User not found");
UserDto userDto = new ModelMapper().map(userEntity, UserDto.class);
/* ErrorDecoder */
List<ResponseOrder> orderList = orderServiceClient.getOrders(userId);
userDto.setOrders(orderList);
return userDto;
}
클래스에서 하드코딩을 하는게 아니라 설정파일에 내용을 가져오는 방식으로 해보겠다
config-service 지정된 폴더에 설정파일 [user-service.yml] 코드 추가
order_service:
url: http://ORDER-SERVICE/order-service/%s/orders
// 추가된 부분
exception:
orders_is_empty: User's orders is empty.
// UserServiceApplication.java에서 Bean 삭제 [컴포넌트로 선언했기 때문]
// FeignErrorDecoder.java
@Component
public class FeignErrorDecoder implements ErrorDecoder {
Environment env;
@Autowired
public FeignErrorDecoder(Environment env) {
this.env = env;
}
@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()),
env.getProperty("order_service.exception.orders_is_empty"));
}
break;
default:
return new Exception(response.reason());
}
return null;
}
}
2. Multiple Orders Service [데이터 동기화 문제]
Orders Service 2개 기동
- Users의 요청 분산 처리
- Orders 데이터도 분산 저장 -> 동기화 문제
- 하나의 Database 사용 -> 물리적으로 떨어진 인스턴스에서 생기는 하나의 DB에 저장하기 위해선 트랜잭션을 잘 관리해야됨
- 각각의 Database를 사용하고 DB간 동기화 -> 1번 Orders Service에서 발생한 데이터를 2번 Order Service가 가지고 있으면 됨. Message Quing Server을 사용함
- Kafka Connector + DB -> 하나의 DB와 Message Quing Server을 같이 사용
Order-Service 2개 기동
한명의 사용자가 5건의 상품을 주문했을 때 1번과 2번 서버가 번갈아가며 DB에 저장되어 있다. 다음시간에 알아보겠다.
1번 Order-service에 3건
2번 Order-service에 2건
'Java > Spring Boot' 카테고리의 다른 글
[MSA] Spring Cloud로 MSA를 개발해보자 11편 [Kafka-2] (0) | 2024.09.06 |
---|---|
[MSA] Spring Cloud로 MSA를 개발해보자 10편 [Kafka-1] (0) | 2024.09.01 |
[MSA] Spring Cloud로 MSA를 개발해보자 8편 [서비스간 통신-1] (0) | 2024.08.29 |
[MSA] Spring Cloud로 MSA를 개발해보자 7편 [설정 정보 암호화] (0) | 2024.08.28 |
[MSA] Spring Cloud로 MSA를 개발해보자 6편 [Spring Cloud Bus] (0) | 2024.08.27 |