프로젝트를 MSA 구조로 진행하며, 서비스 로직에서 다른 서비스의 API 를 호출해야 하는 경우가 빈번하게 생겼다. 이를 RestTemplate 을 통해 해결할 수도 있지만 보다 더 나은, 간편한 기능을 통해 풀어본 내용들을 기록하고 공유하고자 이 글을 작성한다.
🟢 Feign
Feign 은 Netflix 에서 개발된 Http client binder다. Feign 을 사용하면 웹 서비스 클라이언트를 보다 쉽게 작성할 수 있다. Feign 을 사용하기 위해서는 interface 를 작성하고 annotation 을 선언 하기만 하면 된다. 마치 Spring Data JPA 에서 실제 쿼리를 작성하지 않고 Interface 만 지정하여 쿼리실행 구현체를 자동으로 만들어주는 것과 유사하다.
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
public class CatalogServiceApplication {
public static void main(String[] args) {
SpringApplication.run(CatalogServiceApplication.class, args);
}
}
1. @EnableFeignClients 을 사용해야 한다. root package 에 있어야 하며, 그렇지 않은 경우 basePackages 또는 basePackageClasses 를 지정해주어야 한다.
2. @EnableFeignClients 은 지정된 package 를 돌아다니면서 @FeignClient 를 찾아 구현체를 만들어 준다.
예제 코드
CatalogService, 상품 서비스(package)에서 아래의 2가지 기능이 있다.
1. 상품 등록
2. 상품 삭제
상품을 등록할 때 List<String> 형식의 tag 를 추가로 넣어주는데, 이는 검색 서비스(package) 에서 해당 tag로 검색이 가능하게 되어야 하며, 이는 Cache 에 저장되는 형식이다. 그렇기에 상품을 등록하는 동시에 검색 서비스의 Cache 를 추가하는 API 를 호출해야 한다. 아래 코드를 통해 설명을 구체화 해보겠다.
name: FeignClient의 bean name (다른 FeignClient의 name과 겹치면 안됨) url: 해당 client의 base url @GetMapping(value = “/api/”): RequestMethod와 api Path
통신해야 하는 API 는 addTagCache, removeTagCache 2개이다. 각각에 해당하는 Request Method Mapping 을 해주고 value 에 api Path 를 지정해준다.
@Service
public class CatalogService {
// MySQL
@Autowired
SellerProductRepository sellerProductRepository;
// Cassandra
@Autowired
ProductRepository productRepository;
@Autowired
SearchClient searchClient;
// 상품 등록
public Product registerProduct(
Long sellerId,
String name,
String description,
Long price,
Long stockCount,
List<String> tags
) {
// 등록
var SellerProduct = new SellerProduct(sellerId);
sellerProductRepository.save(SellerProduct);
Product product = new Product(
SellerProduct.id,
sellerId,
name,
description,
price,
stockCount,
tags
);
// Open feign
var dto = new ProductTagsDto();
dto.tags = tags;
dto.productId = product.id;
searchClient.addTagCache(dto);
return productRepository.save(product);
}
이제 실제 api 를 호출해야 하는 부분에 dto 를 생성하여 interface 에 작성한 메서드를 호출하기만 하면 된다.
이번 프로젝트에 꽤 많은 시간을 들이고 있다. 실제 회사에서 다루던 결제 서비스를 다른 언어, MSA 구조로 설계해 나가는 과정을 통해 꽤 많은 것들을 느끼며 재미있는 경험을 하고 있다. 앞으로도 더 많은 포스팅을 가지고 오겠다!