공부 내용을 정리하고 앞으로의 학습에 이해를 돕기 위해 작성합니다.
Feign Client
- Feign은 선언적으로 사용할 수 있는 웹 서비스 클라이언트이다.
- 간단히 말해, 코드에서 직접 HTTP 요청을 작성하지 않고, 인터페이스와 애노테이션을 사용하여 HTTP 요청을 수행할 수 있다.
- ref : https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html
Feign Feature
Connection/Read Timeout
- 외부 서버와 통신할 때, 연결 타임아웃(connectTimeout)과 읽기 타임아웃(readTimeout)을 설정할 수 있다.
Feign Interceptor
- 외부로 요청이 나가기 전에 공통적으로 처리해야 하는 부분이 있다면, RequestInterceptor를 재정의하여 처리할 수 있다.
- 예를 들어, 모든 요청에 특정 헤더를 추가하거나 로그를 남기는 등의 작업을 수행할 수 있다.
Feign CustomLogger
- CustomLogger를 사용하면 Feign 클라이언트에서 요청과 응답에 대한 로그를 남길 수 있다.
- 특정 조건에 따라 로그를 남기거나, 특정 응답 시간 이상인 경우 경고를 출력하는 등의 설정이 가능하다.
Feign ErrorDecoder
- 요청에 대한 응답이 정상적이지 않은 경우, ErrorDecoder를 사용하여 예외를 처리할 수 있다.
- 응답 코드에 따라 예외를 던지거나, 로그를 출력할 수 있다.
실습
프로젝트 설정
1. 의존성 추가
ext {
set('springCloudVersion', '2023.0.3')
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
// Feign
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
- 프로젝트에서 Feign 클라이언트를 사용하기 위해 spring-cloud-starter-openfeign 의존성을 추가한다.
- Spring Cloud의 최신 버전과 함께 필요한 의존성을 관리할 수 있도록 spring-cloud-dependencies를 가져온다.
2. Feign 클라이언트 활성화
package dev.be.feign;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients
@SpringBootApplication
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class, args);
}
}
- @EnableFeignClients 애노테이션을 메인 애플리케이션 클래스에 추가하여 Feign 클라이언트를 활성화한다.
- 이렇게 설정하면 Feign 클라이언트를 사용할 준비가 완료된다.
패키지 구조 및 역할
1. 패키지 구성
- config: Feign 관련 설정 파일을 포함하며, Feign 클라이언트의 연결 타임아웃, 읽기 타임아웃, 로거 레벨 등의 설정을 관리한다.
- controller: REST API 요청을 처리하는 컨트롤러 클래스를 포함한다.
- service: 비즈니스 로직을 처리하는 서비스 클래스를 포함한다.
- feign: Feign 클라이언트 인터페이스 및 관련 설정 파일을 포함한다.
- common: DTO(Data Transfer Object) 클래스들을 포함하여 데이터를 전송할 때 사용하는 객체들을 정의한다.
2. Feign 설정
feign:
url:
prefix: http://localhost:8080/target_server # DemoFeignClient?? ??? url prefix ?
client:
config:
default:
connectTimeout: 1000
readTimeout: 3000
loggerLevel: NONE
demo-client: # DemoFeignClient?? ??? Client ?? ?
connectTimeout: 1000
readTimeout: 10000
loggerLevel: HEADERS # ??? ??? ?? FeignCustomLogger -> Logger.Level logLevel ??? ???
# [loggerLevel ??]
# ref : feign.Logger.Level
# ```
# NONE, // No logging.
# BASIC, // Log only the request method and URL and the response status code and execution time.
# HEADERS, // Log the basic information along with request and response headers.
# FULL // Log the headers, body, and metadata for both requests and responses.
# ```
- application.yml 파일에서 Feign 클라이언트의 기본 URL, 타임아웃, 로깅 레벨 등을 설정한다.
- 기본 설정 외에도 특정 클라이언트(demo-client)에 대해 별도의 설정을 적용할 수 있다.
package dev.be.feign.feign.config;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DemoFeignConfig {
}
- DemoFeignConfig: 특정 Feign 클라이언트(demo-client)에 대한 설정을 포함하는 클래스이다. 이 클래스에서 클라이언트의 타임아웃, 로깅 레벨 등을 설정한다.
- 이 설정을 통해 Feign 클라이언트의 동작 방식을 세부적으로 조정할 수 있다.
3. BaseRequestsInfo & BaseResponseInfo 클래스
package dev.be.feign.common.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(Include.NON_NULL)
public class BaseRequestsInfo {
private String name;
private Long age;
private String header;
}
- BaseRequestsInfo: 요청 데이터를 담는 DTO 클래스이다. 클라이언트가 서버로 보내는 이름, 나이, 헤더 정보를 포함한다.
package dev.be.feign.common.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(Include.NON_NULL)
public class BaseResponseInfo {
private String name;
private Long age;
private String header;
}
- BaseResponseInfo: 응답 데이터를 담는 DTO 클래스이다. 서버에서 클라이언트로 반환하는 이름, 나이, 헤더 정보를 포함한다.
이 두 클래스는 요청과 응답 데이터를 캡슐화하여 코드의 가독성과 유지보수성을 높인다.
Feign 클라이언트 구현
Feign Client 인터페이스
package dev.be.feign.feign.client;
import dev.be.feign.common.dto.BaseRequestsInfo;
import dev.be.feign.feign.config.DemoFeignConfig;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(
name = "demo-client",
url = "${feign.url.prefix}",
configuration = DemoFeignConfig.class
)
public interface DemoFeignClient {
@GetMapping("/get")
ResponseEntity<BaseRequestsInfo> callGet(@RequestHeader("CustomHeaderName") String customHeader,
@RequestParam("name") String name,
@RequestParam("age") Long age);
}
- @FeignClient 애노테이션을 사용하여 외부 API를 호출할 Feign 클라이언트를 정의한다.
- 이 인터페이스에는 호출할 API의 엔드포인트와 필요한 요청 파라미터, 헤더 등을 정의한다.
서비스 클래스
package dev.be.feign.service;
import dev.be.feign.common.dto.BaseRequestsInfo;
import dev.be.feign.feign.client.DemoFeignClient;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class DemoService {
private final DemoFeignClient demoFeignClient;
public String get() {
ResponseEntity<BaseRequestsInfo> response = demoFeignClient.callGet("CustomHeader", "CustomName", 1L);
System.out.println("Name : " + response.getBody().getName());
System.out.println("Age : " + response.getBody().getAge());
System.out.println("Header : " + response.getBody().getHeader());
return "get";
}
}
- Feign 클라이언트를 주입받아 실제로 외부 API를 호출하고 그 결과를 처리하는 비즈니스 로직을 구현한다.
- 외부 API 호출 결과를 받아 필요한 정보들을 콘솔에 출력하고, 컨트롤러로 반환한다.
컨트롤러 클래스
package dev.be.feign.controller;
import dev.be.feign.service.DemoService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
@RestController
public class DemoController {
private final DemoService demoService;
@GetMapping("/get")
public String getController() {
return demoService.get();
}
}
- 특정 엔드포인트(/get)를 정의하여 클라이언트 요청을 받아 서비스 클래스에서 정의한 비즈니스 로직을 실행하고 결과를 반환한다.
TargetController 클래스
package dev.be.feign.controller;
import dev.be.feign.common.dto.BaseResponseInfo;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/target_server")
public class TargetController {
@GetMapping("/get")
public BaseResponseInfo demoGet(@RequestHeader("CustomHeaderName") String header,
@RequestParam("name") String name,
@RequestParam("age") Long age) {
return BaseResponseInfo.builder()
.header(header)
.name(name)
.age(age)
.build();
}
}
- 실제 외부 API 역할을 하는 컨트롤러로, Feign 클라이언트가 호출하는 엔드포인트를 정의한다.
- 요청받은 데이터를 바탕으로 응답을 생성하여 반환한다.
실행 결과
- Feign 클라이언트를 사용하여 외부 API에 대한 요청을 성공적으로 보내고, 그 결과를 처리하는 것을 확인할 수 있었다.
- 응답 데이터가 의도한 대로 잘 파싱 되어 출력되었고, 클라이언트 요청에 대해 정확한 응답을 반환할 수 있었다.
이 실습을 통해 Feign 클라이언트를 사용한 외부 API 통신을 실무에서 어떻게 활용할 수 있는지에 대해 학습할 수 있었다. Feign을 사용하면 RESTful API 호출이 더욱 간단하고 선언적으로 이루어지며, 다양한 설정을 통해 유연하게 사용할 수 있다.
'BackEnd > Project' 카테고리의 다른 글
[RealPJ] Ch02. 실무 스타일로 Feign Client 사용해보기 - Logger (3) | 2024.08.30 |
---|---|
[RealPJ] Ch02. 실무 스타일로 Feign Client 사용해보기 - Interceptor (0) | 2024.08.30 |
[RealPJ] Ch02. 비동기 프로그래밍 개념 및 실습 (0) | 2024.08.30 |
[RealPJ] Ch01. Profile 설정 (0) | 2024.08.30 |
[RealPJ] Ch01. Spring Multi Module 개념 및 실습 (2) | 2024.08.30 |