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 에 대한 설명은 아래의 블로그에 잘 설명된것 같다.
    [Spring Reactive] WebClient
 

[Spring Reactive] WebClient

Web Reactive Stack 공식문서의 WebClient 부분을 읽고 해석하며 작성했습니다. Web on Reactive Stack The original web framework included in the Spring Framework, Spring Web MVC, was purpose-built for the Servlet API and Servlet containers.

binux.tistory.com

 

짤막 비교. RestTemplate vs WebClient

신규 전시 프로젝트에서 WebClient 사용하기 | 올리브영 테크블로그

 

신규 전시 프로젝트에서 WebClient 사용하기 | 올리브영 테크블로그

Http Client에 관한 소소한 이야기

oliveyoung.tech

  • 올리브영 테크 블로그
  • 동시 사용자 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

Feign 코드 분석과 서버 성능 개선

 

Feign 코드 분석과 서버 성능 개선

Feign과 다중 스레드를 사용하는 과정에서 생긴 문제를 이해하고 성능 개선까지 한 경험을 공유해요.

toss.tech

 

WireMock 에 대한 좋은 설명과 예시

Wiremock을 이용한 테스트 작성기

 

Wiremock을 이용한 테스트 작성기

지난 Feign Client 적용기에 이어서 WireMock을 이용한 테스트 경험을 소개합니다. 서론 이번 프로젝트에서는 기능 개발 시 인수테스트, 통합테스트, 단위테스트를 먼저 작성하고 개발을 진행하려고

forkyy.tistory.com

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

 

[MSA] Spring Feign Client Test Code

분산환경에서의 테스트코드 작성을 해보았습니다.

velog.io

우아한 테크 Feign 적용기

우아한 feign 적용기 | 우아한형제들 기술블로그

 

우아한 feign 적용기 | 우아한형제들 기술블로그

안녕하세요. 저는 비즈인프라개발팀에서 개발하고 있는 고정섭입니다. 이 글에서는 배달의민족 광고시스템 백엔드에서 feign 을 적용하면서 겪었던 것들에 대해서 공유 하고자 합니다. 소개 Feign

techblog.woowahan.com

 

feign 좀더 나아가기 | 우아한형제들 기술블로그

 

feign 좀더 나아가기 | 우아한형제들 기술블로그

안녕하세요. 저는 상품시스템팀에서 개발하고 있는 고정섭입니다. 이 글에서는 배달의민족 광고시스템 백엔드에서 feign 을 적용하면서 겪었던 것들에 대해서 공유 하고자 합니다. 이 글은 이전

techblog.woowahan.com

Goorvy TestCode (우아한 테크)

GitHub - woowabros/feign-apply-experience-sample

 

GitHub - woowabros/feign-apply-experience-sample

Contribute to woowabros/feign-apply-experience-sample development by creating an account on GitHub.

github.com

공식문서

Spring Cloud OpenFeign

 

Spring Cloud OpenFeign

Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable

docs.spring.io

Baeldung Spring Cloud Feign

Configuring Spring Cloud FeignClient URL | Baeldung

 

728x90
반응형
MyeongDev