https://bestdevelop-lab.tistory.com/174
FeignClient 사용 이유
- 앞서 RestTemplate, FeignClient, WebClient를 비교했을 때 언급하였 듯이, RestTemplate은 더 이상 개발이 되지 않게 되었으며, 아래의 이유들로 RestTemplate보다 FeignClient가 더 선호되는 것 같음
- SpringMvc에서 제공되는 어노테이션 사용 가능
- 기존에 사용되던 HttpClient보다 더 간편하게 사용 가능하며, 가독성이 뛰어남
- 통합 테스트가 비교적 간편
- 사용자 의도대로 커스텀이 간편
FeignClient vs RestTemplate 코드 비교
- 외부 서버의 날씨 API를 호출할 때 RestTemplate으로 작성
@Service
public class WeatherService {
public String getTodayWeather(){
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer ...");
URI uri = UriComponentsBuilder
.fromUriString("http://korea-weather")
.path("/api")
.queryParam("date", "2024-03-16")
.encode()
.build()
.toUri();
return restTemplate.exchange(
uri,
HttpMethod.GET,
new HttpEntity<>(headers),
String.class)
.getBody();
}
}
- OpenFeign으로 작성
@FeignClient(name = "WeatherApi", url = "http://korea-weather")
public interface WeatherApi {
@GetMapping
ResponseEntity getTodayWeather(
@RequestHeader String authorization,
@RequestParam String date);
}
- OpenFeign을 사용할 경우 작성해야할 코드의 양이 비약적으로 감소
- @GetMapping과 같은 Spring MVC 어노테이션 활용도 가능
Gradle 의존성 추가
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
활성화
- main 클래스에 OpenFeign을 사용한다고 선언(@EnableFeignClients)하여 OpenFeign을 활성화
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
@EnableJpaAuditing
@EnableScheduling
@EnableFeignClients
public class PlayheavenApplication {
public static void main(String[] args) {
SpringApplication.run(PlayheavenApplication.class, args);
}
}
FeignClient 구현
@FeignClient(name = "WeatherApi", url = "http://korea-weather")
public interface WeatherApi {
@GetMapping("/v1/list/{day}")
List<RainRes> getRainList(
@RequestHeader("authorization") String authorization,
@PathVariable(name = "day") String day);
@GetMapping("/v1/foggy")
List<FoggyRes> getFoggyList(
@RequestHeader("authorization") String authorization,
@RequestParam(name = "page") Integer page,
@RequestParam(name = "pageSize") Integer pageSize);
@PostMapping("/v1/weather/{createId}")
Response insertSatisfaction(
@RequestHeader("authorization") String authorization,
@PathVariable(name = "createId") Integer createId,
@RequestBody WeatherReq weatherReq);
}
- interface 생성
- @FeignClient 어노테이션 추가
- name 속성 ⇒ Feign Client의 식별자 정의
- Spring Cloud가 서비스 레지스트리(예: Eureka)와 연동해 마이크로서비스 간 통신을 할 때 유용
- 로드 밸런싱 및 서비스 디스커버리를 위해 사용 가능
- url 속성 ⇒ 호출할 URL
- 메서드는 Spring MVC와 거의 동일
- @GetMapping, @PostMapping 등을 사용하여 경로를 작성하면 최상단의 url 뒤에 추가가 되는 것 같음
- Ex) @GetMapping("/v1/list/{day}") ⇒ http://korea-weather/v1/list/{day}로 요청
- @RequestHeader, @RequestParam, @PathVariable 등 모두 사용이 가능하며, POST의 경우 @RequestBody로 JSON 요청 또한 가능
- Ex) 외부 API에 'http://korea-weather/v1/whether/{createId}' 라는 URL로 POST 요청
- 외부 API에서 해당 URL을 처리하는 메서드에는 헤더에 인가 정보, createdId가 url 경로에 포함되고, WeatherReq 객체를 JSON으로 받는 매개 변수가 존재
- @GetMapping, @PostMapping 등을 사용하여 경로를 작성하면 최상단의 url 뒤에 추가가 되는 것 같음
@Service
@RequiredArgsConstructor
public class WeatherService {
private final WeatherApi weatherApi;
public List<RainRes> getRainListByWeatherApi(String authorization, String day) {
...
return weatherApi.getRainList(authorization, day);
}
}
- Service 클래스에서 생성한 인터페이스(WeatherApi)를 DI하여 사용하면 됨
Configuration의 활용
로깅(Logging)
public class WeatherApiConfig {
@Bean
Logger.Level weatherApiLoggerLevel() {
return Logger.Level.FULL;
}
}
- Logger 레벨
- NONE : 로깅 X (기본값)
- BASIC : 요청 메서드, URI, 응답 상태, 실행시간 로깅
- HEADERS : 요청, 응답헤더 및 기본 정보들 로깅
- FULL : 요청, 응답 헤더 및 바디, 메타 데이터를 로깅
- OpenFeign의 로그는 DEBUG 레벨로만 남길 수 있기 때문에 로그 레벨을 DEBUG로 설정
- application.yml 파일
logging:
level:
com.openfeign.package: DEBUG
- configuration은 @FeignClient 속성으로 지정이 가능하고, 두 개 이상의 configuration 설정 또한 가능
@FeignClient(
name = "WeatherApi",
url = "${external.weather.api}",
configuration = {WeatherApiConfig.class})
public interface WeatherApi{
...
}
재시도
public class RetryConfig {
@Bean
public Retryer feignRetryer() {
// 0.1초 간격에서 최대 1초 간격으로 최대 3번 재시도
return new Retryer.Default(100, 1000, 3);
}
}
- configuration에서 API 요청을 재시도하는 간격을 설정 가능
- 다만 위에서 사용한 Retryer는 IOException이 발생한 경우에만 동작
- 다른 예외에도 재시도를 하고 싶다면 인터셉터를 직접 구현해야 함
@FeignClient(
name = "WeatherApi",
url = "${external.weather.api}",
configuration = {WeatherApiConfig.class, RetryConfig.class })
public interface WeatherApi{
...
}
- 2개 이상의 configuration 설정
공통 헤더 적용
- 매번 메서드에 @RequestHeader로 보안 토큰을 넣어주는 것은 매우 귀찮고 비효율적
public class HeaderConfiguration {
@Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> requestTemplate.header("Authorization", "Bearer ...");
}
}
- 위와 같이 configuration에서 RequestInterceptor를 설정하여 원하는 헤더를 설정
- 위 configuration을 FeignClient에 적용시키면 모든 메서드에 Header가 설정
참고 자료
OpenFeign 이란? OpenFeign 사용법 : https://code-lab1.tistory.com/414
OpenFeign이 아직 감이 잡히지 않을 경우(클라이언트와 서버로 간단 코드 구현) : https://targetcoders.com/openfeign-%EC%98%88%EC%A0%9C/
'MicroService Architecture' 카테고리의 다른 글
[API Gateway] API Gateway Filter (0) | 2024.08.28 |
---|---|
API Gateway 라이브러리 선택 및 사용 예제 (0) | 2024.08.23 |
Feign Client / Web Client / RestTemplate (0) | 2024.08.21 |
[Spring Cloud] Netflix Eureka 개념, 용어 정리 및 사용 예제 (0) | 2024.08.20 |
Service Discovery 개념, 종류, 특징 (0) | 2024.08.20 |