brunch

You can make anything
by writing

C.S.Lewis

by 에디의 기술블로그 Jun 16. 2019

Spring Cloud Openfeign

HTTP Client, Java Library

이번 주말에는, Spring-Cloud-OpenFeign 에 대해서 공부한 내용을 공유하고자 한다. Feign 을 살펴보기 전에 기본적인 HTTP Client Java Library 에 대해서 먼저 알아보고, Spring Cloud Openfeign 기본적인 내용과 심화 내용을 정리하였다. 잘못된 내용은 꼭 댓글을 남겨주길 바란다. 



1. HTTP Client, Java Library


Spring Cloud Openfeign 을 알아보기 전에, 일반적으로 많이 사용하는 HTTP Client 자바 라이브러리를 소개한다. 상세한 내용은 생략하고, 간략한 소개 수준으로 공유한다. 


1.1 HttpURLConnection


HttpURLConnection 은 JDK 에 포함되어 있는 가장 기본적인 클래스이며, 일반적으로 아래와 같은 코드를 작성해야 한다.

HTTP Connection 오픈

HTTP 요청 방식(메서드) 설정

Connection 타임아웃 설정

Header 설정

응답 Content Type 설정

호출 및 응답 내용 받기

접속 해제

이버 오픈API 호출 샘플 코드를 참고하자. 

https://developers.naver.com/docs/common/openapiguide/apicall.md

HTTP 한번 호출을 하기 위해서 많은 코드를 작성해야 한다. 다른 블로그 글을 보면, HTTP Client 라이브러리를 사용하는 것보다, HttpURLConnection 를 사용하는 방법이 성능이 더 좋다는 글을 본적이 있다. 하지만, HttpURLConnection 를 그대로 사용하는 것은 다소 생산성이 떨어지는 단점이 있다. 


1.2 New HTTP Client in Java 9


JDK 9 버전에서 HttpURLConnection 을 대체할 수 있는 새로운 HTTP Client 가 등장하였다. HTTP/2 프로토콜을 지원하며 동기/비동기 모드를 지원한다. 관련해서는 필자가 자세히 모르기 때문에 상세한 내용은 생략하겠다. 링크를 참고하길 바란다. 

https://www.baeldung.com/java-9-http-client


지금까지는 JDK 에서 기본적으로 제공하는 클래스를 알아봤는데, 소스 코드가 길어지고 구현하기 조금 까다로운 단점이 있다. 그래서 대부분의 개발자는 HTTP 통신을 제공하는 좋은 라이브러리를 사용한다. Apache Commons HttpClient, Apache HttpComponents, OkHttp, Retrofit, feign 등 많은 라이브러리가 있고, 전부 오픈소스 프로젝트이다. 


1.3 Apache Commons HttpClient


아주 오래 전에 사용하던 Apache 에서 만든 오픈소스 라이브러리이다. 3.1 버전까지 나오고 중단되었다. 4.X 버전부터는 패키지명이 바뀌어서 새로운 이름으로 바뀌었는데, 그 이름은 바로 HttpComponents 이다. 


1.4 Apache HttpComponents


기존 레거시(Apache Commons HttpClient)의 단점을 보완해서 새로운 패키지로 발표되었는데, 안정적인 기능을 제공하는 오픈소스 라이브러리이다. JDK 에서 기본으로 제공하는 HttpURLConnection 보다는 무겁지만, 다양한 API 제공하기 때문에 매우 유용하다. 샘플 코드는 생략하겠다. 


1.5 Restemplate


RestTemplate 이란, Spring 3.0 부터 지원하는 Http 통신에 사용하는 스프링 환경에서의 HTTP Client 코드이다. 반본적인 코드를 깔끔하게 정리해주고, Restful 원칙을 지키며 Json, Xml 등 쉽게 요청/응답을 받을 수 있다. RestTemplate 은 Http를 사용하는 범용 라이브러리인, HttpClient 를 추상화해서 제공하며, 스프링을 사용하는 개발자라면 모르는 개발자가 없을 정도로 많이 사용한다.


1.6 Retrofit


Square 라는 회사에서 만든 오픈소스 라이브러리이다. OKHttp 가 적용되어 있고, 안드로이드 환경에서 특히 많이 사용된다고 들었다. 자세한 내용은 생략하겠지만, 추후에 필자가 스프링부트 환경에서 Retrofit 를 적용한느 방법에 대해서 공유를 할 예정이다.


1.7 Feign


NetFlix 에서 만든 선언적 Rest Client 라이브러리이다. RestTemplate 대체로 사용할 수 있고, Spring Cloud 프로젝트에서 매핑해서 제공해주고 있다. 이번 글에서 주인공인 라이브러리이다. 자세한 내용은 잠시 후 다시 설명하겠다.  


1.8 Webclient


스프링 5 환경에서 리액티브 프로그래밍을 위한 Reactor로 작성된 HTTP Client 이다. 

https://www.baeldung.com/spring-5-webclient


1.9 기타 등등


이 글에서 전부 작성하기 어렵지만, 기타 라이브러리가 꽤 많다. 어떤 라이브러리를 사용하면 좋은지에 대한 정답은 없다. 각자 개발환경에 적합한 라이브러리를 선택하길 바란다. 필자는 현재 RestTemplate 또는 Webclient 를 선호하고, 이 글에서 집중적으로 다루고 있는 Feign 에 조금 관심을 갖고 있다. RestTemplate, WebClient, Feign 등 장단점이 있고, 어떤 한 기술만 정답인것처럼 사용하는 것보다는 상황에 맞게 잘 사용해야 한다. 


2. RestTemplate


Spring Cloud Openfeign 을 알아보기 전에 먼저, RestTemplate 에 대해서 알아보자. 대부분 개발자가 잘 알고 있기 때문에 상세한 내용은 생략하고, 아주 간략하게만 다룬다. 


2.1 RestTemplate


RestTemplate 를 사용해서 네이버 오픈 API 연동 코드를 구현하였다. 

참고로, 필자의 코드에서 RestTemplate를 인스턴스 생성하였는데, 보통 이렇게 하지 않고, RestTemplate 빈을 정의한 후 필요한 곳에서 주입해서 사용해야 한다. RestTemplate 는 기존에 사용하던 HttpURLConnection 이나 Apache HttpComponents 보다 훨씬 편리하다. 그래서 RestTemplate 는 매우 쉽게 Rest 서비스를 호출할 수 있기 때문에 실무에서 자주 사용되고 있다. 하지만, 아주 쉽고 편리하지만 그럼에도 불구하고 아래와 같은 작업들을 반복적으로 수행해야 한다. 

RestTemplate 인스턴스 또는 DI 주입

타겟 URL 정의

Request 헤더 설정

Contents 타입 설정

URL 호출


2.2 RestTemplate vs Feign


필자의 경험으로는, RestTemplate 는 시간이 지날수록 유지보수하기 어렵다. 불필요한 코드를 반복적으로 작성해야 하고, 테스트하기도 쉽지 않다. 반면에, Feign 은 선언적으로 인터페이스를 작성하고 어노테이션을 선언하기만 하면 되기 때문에 매우 심플하다. 테스트도 간편하기 때문에 RestTemplate 에 비해서 클라이언트 코드를 보다 쉽게 작성할 수 있다. 이 글에서, RestTemplate 와 Feign 을 비교하는 내용은 아주 상세하게 작성하지 않겠다. 아래 동영상을 참고하길 바란다. 

https://www.youtube.com/watch?v=4Y3_V-QOBKc&t=1s



3. Spring Cloud Openfeign(1) - 기초


본격적으로 Spring Cloud Openfeign 을 알아보겠다.


3.1 Spring Cloud Openfeign 


Feign 은 넷플릭스에서 개발한 오픈소스이며, 선언적 방식으로 Rest 기반 호출을 추상화해서 제공한다. 스프링 환경에서 Feign 을 잘 사용하기 위해서, Spring-Cloud-Openfeign 를 사용하면 된다. 


3.2 디펜던시


필자는 JDK 1.8, 스프링부트 2.1.5.RELEASE (Gradle), IntelliJ 환경에서 코드를 작성되었다. 

스프링 클라우드 버전은 Greenwich.SR1 이고, spring-cloud-starter-openfeign 을 디펜던시로 추가하였다. 그리고, Lombok 을 사용할 예정이므로 Intellij 에서 Enable annotation processing 을 체크하도록 하자. 



3.3 @EnableFeignClients


Feign 을 사용하기 위해서는 먼저 @EnableFeignClients 를 선언해야 한다. 

최상위 Package 에 선언한다. @EnableFeignClients 어노테이션을 붙이면, @FeignClient 를 선언한 인터페이스를 찾아서 구현체를 자동으로 만들어준다. 


3.4 @FeignClient


네이버 오픈API 를 호출하는 @FeignClient 를 아래 코드와 같이 정의하였다. 선언적 인터페이스를 작성해준다.

@FeignClient 

FeignClient 를 선언해줄 때 url 주소를 포함하였다.(추후에 다시 설명하겠지만, 유레카에 연동되어있다면 url 주소는 생략하고, 애플리케이션 이름을 명시해주면 된다.) 필자는 application 프로퍼티에서 설정한 값이 들어가도록 코딩하였는데, 프로퍼티에 정의된 "https://openapi.naver.com" 가 매핑된다.  fallback 은 API 호출 시 발생하는 예외 처리를 위한 클래스를 정의한다. 


@RequestMapping, @RequestHeader, @RequestParam

상세 API를 호출하는 Spring MVC 매핑 metadata 를 정의해준다. value 에는 url 주소뒤에 붙는 나머지 주소를 설정해준다. 필자의 샘플 코드에서는 네이버 오픈 API 중 블로그 정보를 조회할 것이다. 네이버 개발자 도구에서 제공하는 가이드를 바탕으로  "/v1/search/blog.json" 를 설정하였다. produces 에는 응답 타입을 지정해준다. @RequestHeader 에는 Request Header 값을 설정할수 있는데, 네이버 오픈 API 호출을 위한 인증 값을 전달해준다. 해당 값이 누락되면 API 호출시 인증 문제가 발생할 것이다. 

인증키 값은 개발자도구에서 각자 신청해야 한다. 샘플코드를 실행하고 싶다면 네이버 개발자 도구에 다녀오길 바란다. 


3.5 Service


서비스에서 Feign 클라이언트 메서드를 호출해보자. @FeignClient 로 선언한 NaverOpenApiClient 를 의존성 주입해서 사용한다. 

이때, 필자는 메서드 호출 시 인증 값을 넘겨주기 위해서, EnableConfigurationProperties 를 사용해서 별도로 정의한 프로퍼티 클래스를 설정하였다. 

인증키 값은 비밀이다. 네이버 개발자 센터에서 쉽게 인증키를 신청할 수 있다.

추가로, 응답 데이터를 매핑해주기 위한 클래스도 하나 만들자.


3.6 Controller 


컨트롤러를 하나 만들어서 테스트를 해보자.

호출하면 정상적으로 Open API 데이터를 조회할 수 있다. 


3.7 정리


Feign 을 적용해서 기본적인 HTTP Client 연동 방법에 대해서 알아보았다. 다음 장에서는 심화 내용을 공부할 것이다. 


4. Spring Cloud Openfeign(2) - 심화


사실... 필자는 심화 과정을 설명할 만큼 전문가는 아니다. 잘못된 내용이 있다면 댓글로 피드백을 해주길 바란다. 


4.1 AutoConfiguration


시간 관계상 자세한 내용은 생략한다. 코드를 꼭 확인해보길 바란다.


4.2 Hystrix Fallback


Fallback 을 테스트하기 위해서, 임시로 장애를 발생시켜보자. 일단, 프로퍼티 설정으로 Connection Timeout 을 1ms 로 변경하였다. 

IT기술이 발전하면서, 네트워크 기술 역시 많은 발전을 하였지만, Open API 응답을 1ms 안에 응답받는건 쉽지 않은 일이다. 특별한 작업(Fallback)을 하지 않았다면 아래와 같이 커넥션 타임아웃 오류가 발생할 것이다. 

Fallback 를 동작시키기 위한, hystrix 설정을 해주자. 

그리고, @FeignClient가 선언된 인터페이스를 구현하는 Fallback 구현체를 작성하자.

@FeignClient 어노테이션에 Fallback 클래스를 설정해준다.

자... 이렇게 설정하면, Fallback 이 동작할 것이다. 에러 메시지를 노출시키지 않고, 필자가 정의한 ResponseNaverBlog.EMPTY 가 리턴될 것이다. 


하지만, Fallback 이 발생하였지만, 정확히 어떤 오류인지 알 수가 없다. 정확한 Exception 처리를 하기 위해서는 Fallback Factory 를 사용해야 한다. 


4.3 Fallback Factory


FallbackFactory 를 구현하는 NaverOpenApiClientFallbackFactory 라는 클래스를 신규로 정의하였다.

참고로, 위 샘플코드는 아래와 같이 줄일 수 있다.

그리고, @FeignClient 어노테이션에서 NaverOpenApiClientFallbackFactory 설정을 해준다. 기존 fallback 설정은 주석처리하였다. 

이렇게 설정하고 에러를 발생시키면 Throwable 변수에 어떤 에러인지 Exception 정보가 포함되어 있다. 단, 초기에 스프링부트 애플리케이션이 실행이 되고, 최초 Request 요청시에 오류를 강제로 발생시킨다. 이유는 잘 모르겠다. 특별한 문제가 없는데도 fallback 을 수행한다. 이 부분에 대해서는 필자가 정확히 원인을 찾지 못했고, 다른 블로그의 글에서도 필자와 동일한 문제 제기를 한 글을 찾을 수 있다. 나중에 알게 되면 그때 다시 공유하겠다. 지금은 바쁘니깐 대충 넘어간다. 


4.4 Overriding Feign Defaults


필자가 작성한 네이버 오픈API 호출 샘플코드를 보면, @FeignClient 메서드를 호출할 때 Request Header 로 인증 데이터를 매개변수로 넘겨주고 있다. 매번 Header 를 넘겨줘야 하는가? 해당 로직을 configuration 를 사용해서 개선해보자. 

https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html#spring-cloud-feign-overriding-defaults

브런치에 작성하는 글인데 네이버 오픈 API만 사용하면 좀 서운할테니, 이번에는 카카오 API를 사용해보겠다. 호출해보겠다. @FeignClient 어노테이션을 정의하고 신규 interface 를 작성한다. 이때 중요한 점은, configuration = "" 에서 커스텀하게 작성한 Configuration 클래스를 설정해준다는 점이다. 필자는 KaKaoOpenApiConfiguration 이라는 클래스를 만들었다. 

KaKaoOpenApiConfiguration 클래스에서는 RequestInterceptor @Bean 생성하는 메서드를 추가하였다. 

카카오 API 를 호출하기 위한 인증 Header 값을 필자가 별도로 작성한 Configuration 클래스에서 설정해주고 있다. 이제, 메서드를 호출할 때 굳이 매번 Header 를 전달하지 않아도 된다. 아주 중요한 내용이다.


4.5 Eureka


Spring Cloud Eureka 와 연동했을 때 어떻게 동작하는지 알아보기 위해서, 아래와 같이 아주 간단한 시스템을 구축하였다. 사용자가 test-api 에 요청을 하면, test-a 는 test-b-01 또는 test-b-02 를 호출한다. test-b-01 은 "green" 이라는 값을 리턴하고, test-b-02 는 "blue" 라는 값을 리턴해준다. 


Eureka 서버

Eureka 서버는 8888 포트로 지정하였다. Eureka 서버 구축 관련해서 상세한 내용은 생략하겠다. 


test-b-0[1-2] 

해당 서버 두대는 application 이름을 동일하게 "test-b" 로 설정하였다. 즉, 같은 기능을 제공하는 애플리케이션 2대를 구축하는 것이다. Eureka Client 디펜던시를 추가하고, application.yml 에 Eureka 서버를 지정해줘야 한다. test-b-01 는 8081 포트로 실행하고, test-b-02 는 8082 포트로 실행하였다. 

test-a

test-a 서버에서는, Feign 라이브러리를 사용해서 test-b-01,02 를 호출할 것이다. 단, 위에 샘플에서 소개한 방식이랑 다르게 application.name 을 지정해줄 것이다. 기존에는 url 에 API 주소를 지정해줘서 호출했지만, 이번 샘플은 url 을 따로 지정해주지 않는다. @FeignClient 어노테이션에 호출해야하는 애플리케이션 이름을 지정해준다. 

그럼, test-b 라는 이름의 애플리케이션 url 은 어떻게 알 수 있을까? 바로 Eureka 서버에서 알려준다. test-a 는 Eureka 서버로부터 test-b 애플리케이션의 인스턴스 url 주소를 받을 수 있다. 유레카 대시보드를 확인해보면, 아래와 같이 인스턴스 정보를 확인할 수 있다. 

test-a 에는 1개의 인스턴스가, test-b 에는 2개의 인스턴스가 등록되어있는 것을 확인할 수 있다. test-a 에서 호출하는 test-b 는 로드밸런스 되어서 호출할 것이다. 만약에 test-b 서버 중 1대가 장애가 발생하면 어떻게 될까? test-b 중 장애가 발생한 장비는 Eureka 에서 빠지게 될 것이다. Eureka 서버 로그에는 아래와 같이 인스턴스에서 빠졌다는 로그가 쌓이게 된다. 

test-a 에서는 test-b 애플리케이션 중 정상적으로 실행중인 인스턴스 리스트를 Eureka 서버를 통해서 알 수 있기 때문에, test-b 장비 중 1대가 장애가 발생해도, test-a 서버가 test-b 장애 서버를 호출하지 않을수 있다. 이번 글에서 Eureka 에 대한 내용을 전부 다루기는 어렵다. 나중에 기회가 되면 Eureka 관련해서 각잡고 글을 작성하겠다. 


샘플 코드는 아래 github 을 참고하면 된다. 

https://github.com/sieunkr/spring-cloud


Spring Cloud Eureka 에 대한 상세한 내용은 아래 신규 글을 읽어주세요~

https://brunch.co.kr/@springboot/451



5. 마무리


이번 글에서는, Spring-Cloud-Openfeign 에 대해서 공부한 내용을 간략하게 공유하였다. 사실, 필자는 실무에서 RestTemplate 를 주로 사용하기 때문에 Feign 를 사용할 일이 거의 없었지만, 이번에 살펴본 결과 꽤 괜찮고 RestTemplate 를 대체하기에 충분하다는 판단이다. 물론, 일부 기능제한으로 인해서 Feign 을 커스터마이징해서 사용해야할 수도 있지만, 마이크로서비스 아키텍처 환경에서 스프링 클라우드 프로젝트를 핵심 기술로 사용한다면, Spring Cloud Openfeign 을 도입하는 것은 좋은 선택이 될 것이다. 


레퍼런스

https://www.youtube.com/watch?v=4Y3_V-QOBKc&t=1s

http://woowabros.github.io/experience/2019/05/29/feign.html

https://supawer0728.github.io/2018/03/11/Spring-Cloud-Feign/

https://www.blazemeter.com/blog/Rest-API-testing-with-Spring-Cloud-Feign-Clients

https://tech.target.com/2018/12/18/spring-feign.html

https://www.baeldung.com/spring-cloud-openfeign

https://www.javainuse.com/spring/spring-cloud-netflix-feign-tutorial

https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html

https://cloud.spring.io/spring-cloud-static/spring-cloud-openfeign/2.1.2.RELEASE/single/spring-cloud-openfeign.html

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari