728x90
반응형
Feign 란?
- Feign은 Neflix에서 개발된 HTTP Client binder 이다.
- Feign을 이용하면 HTTP Client를 보다 쉽게 작성할 수 있다.
- RestTemplate, WebClient , HttpURLConnection (설마 아직도 이걸 직접…?) 을 사용하는것보다 확실히 훨씬 직관적이고 코드도 간결하다.
Feign 기초 셋팅
의존성
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@EnableFeignClients
@SpringBootApplication
@EnableFeignClients
// @EnableFeignClients(basePackages = "com.example.clients") 명시적 선언
public class FeignClientTestApplication{
public static void main(String[] args) {
SpringApplication.run(FeignClientTestApplication.class, args);
}
}
application-dev.properties
feign.client.url=http://example.com
application-dev.yml
feign:
client:
url: <http://example.com>
Feign Client 기본 사용법
Feign Client Interface
@FeignClient(name = "testClient", url="${feign.client.url}")
public interface StoreClient {
@GetMapping("/stores")
List<Store> getStores();
@GetMapping("/stores")
Page<Store> getStores(Pageable pageable);
@PostMapping("/stores/{storeId}")
Store update(@PathVariable("storeId") Long storeId, Store store);
@DeleteMapping("/stores/{storeId}")
void delete(@PathVariable Long storeId);
}
Controller
@RestController
public class StoreController {
private final StoreClient storeClient;
public StoreController(StoreClient storeClient) {
this.storeClient = storeClient;
}
@GetMapping("/test")
public ResponseEntity test() {
List<Store> stores = storeClient.getStores();
// some logic ...
return ResponseEntity.ok(stores);
}
이런식으로 명시적으로 간결하게 HTTP Client 요청을 보내는 코드를 작성할 수 있다.
다른 HTTP 요청 코드들과 비교
RestTemplate
- Spring 3.0 부터 지원
- RESTful 형식을 지원
- 멀티 스레드 방식
- Blocking I/O기반의 동기 방식 API
- Spring 4.0에서 비동기 문제를 해결하고자 AsyncRestTemplate이 등장했으나, 현재 deprecated 됨
REST Clients :: Spring Framework
RestTemplate is in maintenance mode, with only requests for minor changes and bugs to be accepted. Please, consider using the WebClient instead.
RestTemplate 의 경우 공식문서 상에서 레거시로 간주한다고 한다.
그러나, 아예 Deprecated 되는것은 아니라 유지보수로 간다고 한다.
코드
@Component
@RequiredArgsConstructor
public class StoreAdaptor {
private final RestTemplate restTemplate;
private final String GET_STORES_URL = "<http://example.com>";
public List getStores() {
HttpHeader headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return restTemplate.exchange(
GET_STORES_URL,
HttpMethod.GET,
new HttpEntity<>(headers),
new ParameterizedTypeReference<list>{}
).getBody();
)
</list
- RestTemplate 으로 작성하게 되면 코드가 명확해진다.
- 그러나, 반복적인 작업이 확실히 많이 필요하게 된다.
WebClient
WebClient 특징
- Spring 5.0 부터 지원
- 싱글 스레드 방식
- Non-Blocking 방식, 동기/비동기 모두 지원
- Reactor 기반의 Functional API (Mono, Flux)
@Component
@RequiredArgsConstructor
public class Test {
private final WebClient webClient;
private final String GET_STORES_URL = "<http://example.com>";
public List getStores() {
return webClient.get()
.uri(GET_STORES_URL)
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(new ParameterizedTypeReference<list>() {})
.block();
}
}
</list
- WebClient 의 경우에도 요청에 필요한 코드가 이정도이다.
- 또한, WebClient 의 경우 WebFlux 의 개념인 Mono 의 이해도가 요구된다.
- 단순한 Blocking 방식의 요청을 보내기엔 Feign 이 더 낫다고 생각된다.
- 물론, WebFlux 환경의 코드를 작성하고 Blocking NonBlocking 에 대해서 직접적으로 컨트롤 하려면 WebClient 가 더 적합하다고 생각된다.
- WebClient 에 대한 설명은 아래의 블로그에 잘 설명된것 같다.
짤막 비교. RestTemplate vs WebClient
신규 전시 프로젝트에서 WebClient 사용하기 | 올리브영 테크블로그
- 올리브영 테크 블로그
- 동시 사용자 1000명 미만에서는 RestTemplate 과 WebClient 모두 비슷한 응답속도
- 그러나, 동시 사용자 1000명이 넘어갈 경우 RestTemplate의 성능이 크게 떨어짐.
그럼 Feign은 WebFlux 환경에서 사용 못함?
- Feign 의 경우에 기본적으로 서블릿 기반 애플리케이션을 위해 설계되었다.
- WebFlux 는 비동기 및 논블로킹 웹 애플리케이션을 위한 Reactive Framework
- Feign 은 내부적으로 HttpClient 를 사용하여 HTTP 통신.
- 두 개의 사용 목적이 다르기때문에 WebFlux 환경에서는 더 적합한 WebClient 를 사용하는게 맞지 않을까 하는 생각이다.
Feign Configuration
필수라고 생각되는 설정만 몇개 작성해 보았다.
그 외의 설정은 팀 혹은 개인의 성향에 맞게 설정하면 될 것이다.
@Configuration
public class FeignConfiguration {
/**
* Feign의 기본 로그 레벨 설정
* NONE: 로그X DEFAULT
* BASIC: Request Method, URL, 응답코드, 실행시간
* HEADERS: Request Header,Response Header, BASIC의 요청 정보
* FULL: Body, meta-data, HEADERS의 요청 정보
*/
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
/**
* Requeest Header Default Value Setting
*/
@Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> {
requestTemplate.header("Content-Type", "application/json");
requestTemplate.header("Accept", "application/json");
};
}
/**
* HTTP GET 요청 시 RequestParam 값으로 LocalTime을 보낼 경우
* urlEncoded 되지 않고 ISO Format을 이용함.
*/
@Bean
public FeignFormatterRegistrar localDateFeignFormatterRegister() {
return registry -> {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(registry);
};
}
/**
* Custom Error Decoder
*/
@Bean
public ErrorDecoder errorDecoder() {
return new CustomFeignErrorDecoder();
}
}
public class CustomErrorDecoder implements ErrorDecoder {
@Override
public Exception decode(String methodKey, Response response) {
switch (response.status()){
case 400:
return new BadRequestException();
case 404:
return new NotFoundException();
default:
return new Exception("Generic error");
}
}
}
Retryer은 필수 아닌가?
@Bean
public Retryer retryer() {
/*
* period: 1000
* maxPeriod: 2000
* maxAttempts: 3
*
* 1초를 시작으로 최대 2초로 재시도, 최대 3번
*/
return new Retryer.Default(1000, 2000, 3);
}
- Configuration 에 등록하게 되면 모든 실패한 Feign 에 대해서 Retry 가 일어나게 된다.
- API Call 의 실패 처리는 각 API마다 다를 수 있다고 생각한다.
- 사실 어떤 부분이 정답인지 모르겠다.
@Retryable(backoff = Backoff(delay = 500L), maxAttempts = 3)
@GetMapping("/stores")
public List<Store> getStores()
- 이와 같이 @Retryable 애너테이션을 통하여 각각 컨트롤 할 수 있으니 필요하면 사용하도록 하자.
만약 다른 Configuration 설정이 필요하다면?
@FeignClient(name = "testClient", url="${feign.client.url}", configuration="{OtherConfiguration.}")
public interface StoreClient {
@GetMapping("/stores")
List<Store> getStores();
}
- 단, 여기서 같은 bean 설정이 있다면 @FeignClient configuration attribute 로 설정한 것으로 덮어 씌워진다.
- 해당 부분을 잘 고려해서 사용하자.
참고 및 TestCode
Feign Client 코드 분석과 성능개선 Toss
WireMock 에 대한 좋은 설명과 예시
Feign Client With Eureka Integreation Test Code
Integration Tests With Spring Cloud Netflix and Feign | Baeldung
WireMoke Dependency를 이용한 Feign Client Test Code(Java)
[MSA] Spring Feign Client Test Code
우아한 테크 Feign 적용기
Goorvy TestCode (우아한 테크)
GitHub - woowabros/feign-apply-experience-sample
공식문서
Baeldung Spring Cloud Feign
Configuring Spring Cloud FeignClient URL | Baeldung
728x90
반응형