MSA 구조에서는 마이크로 서비스들이 서로 소통하기 때문에 기존의 모놀리식 보다도 더 많은 소통이 생긴다.
그럴 때 REST 호출을 도와주는 Http Client Binder가 Feign Client 이다.
(이것도 feat. Netflix)
간단히 요약하면, MSA간 통신을 위한 기술이라고 할 수 있다.
기존의 RestTemplate 으로도 호출은 문제 없다.
다만 번거롭다.
다른 설명 글을 보면 주로 JPA에 빗대서 설명하고 있는데, 나 또한 그런 설명이 좋아보인다.
DB에 접근하는 방식을 직접 하나하나 쓰고 있던 과거의 여러 방식들에 비하면 JPA는 인터페이스만으로 그 과정을 모두 축소시킨다.
마찬가지로, Feign을 적용하면 번거로운 RestTemplate과 같은 호출 방식을 인터페이스 하나만으로 축소시킬 수 있다.
다만, JPA를 아직 모르는 사람이 있을 수도 있으므로 다른 방식으로도 설명해보자면
우리가 Lombok을 적용해서 @Getter @Setter를 만들때도 사실 그런걸 사용하지 않고 그냥 게터 메서드와 세터 메서드를 만들어줄 수 있다.
하지만 당연히 어노테이션으로 해결하는게 개발하기에 편할 뿐만 아니라 가독성 증대까지 가져오므로 좋은 선택인 것처럼 Feign도 마찬가지다.
https://spring.io/projects/spring-cloud-openfeign
위의 주소에 들어가보면 기본적인 샘플과 요약을 살펴볼 수 있다.
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
@EnableFeignClients
@SpringBootApplication
@EnableFeignClients
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
@FeignClient("name")
static interface NameService {
@RequestMapping("/")
public String getName();
}
}
@org.springframework.cloud.openfeign.FeignClient(name = "product-service", url = "http....")
public interface FeignClient {
@GetMapping("/buy")
ResponseForm buy(@RequestParam("name") String name);
}
Feign client를 꼭 MSA에서만 써야하는 건 아니지만, 주로 MSA 구조에서 쓰기 때문에 Eureka와 병합해서 사용하는 것은 거의 당연하다고 볼 수 있다.
때문에 단순히 기본 실습 코드만 보기보단, 유레카를 적용해서 실제로 어떻게 동작하는지 구체적으로 보는게 좋을거라고 생각한다.
GitHub - https://github.com/SheepEatLion/eureka_server.git ← 유레카 서버
GitHub - https://github.com/SheepEatLion/msa-spring-cloud-gateway.git ← 스프링 클라우드 게이트웨이 [9000port]
GitHub - https://github.com/SheepEatLion/msa-product-service.git ← 상품 서비스 [8080port]
GitHub - https://github.com/SheepEatLion/msa-shop-service.git ← 주문 서비스 [8081port]
위의 코드는 실습을 위해 직접 간이로 만들어본 서비스와 서버들이다.
스웨거가 적용되어 있으므로 편하게 테스트 해볼 수 있다.
유레카와 함께 feign을 사용하면 feign의 url은 적지 않아도 된다. (서비스 네임으로 탐색하기 때문)
@org.springframework.cloud.openfeign.FeignClient(name = "product-service")
public interface FeignClient {
@GetMapping("/buy")
ResponseForm buy(@RequestParam("name") String name);
}
@RequiredArgsConstructor
@Service
public class ShopService {
private final ShopRepository shopRepository;
private final FeignClient feignClient;
public ResponseForm order(String cName, String pName){
Shop shop = Shop.builder().customerName(cName).build();
shopRepository.save(shop);
return feignClient.buy(pName); <-- 여기
}
}
끝-!