이번 프로젝트에서 FeignClient를 이용하여 개발해서 개념을 이해하고자 공부해보았다.
특히 공통 헤더를 추가하기 위해 커스터마이즈한 Configuration을 설정하는 부분에 대해 정리하였다.
Feign Client란?
1) Feign Client는 web service 클라이언트를 보다 쉽게 작성할 수 있도록 도와줌.
2) interface를 작성하고 annotation을 붙여주면 세부적인 내용 없이 사용할 수 있기 때문에 코드 복잡도가 낮아짐.
3) Netflix 에서 만들어진 Http client binder
4) spring-cloud-starter-openfeign으로 스프링 라이브러리에서 사용할 수 있음.
feign client 라이브러리 넣기
<!-- maven (pom.xml) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.0.3</version>
</dependency>
<!-- gradle(build.gradle) -->
dependencyManagement {
imports {
mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Greenwich.RELEASE'
}
}
dependencies {
//...
// Feign Client
compile 'org.springframework.cloud:spring-cloud-starter-openfeign'
//...
}
Application.java 파일에 annotation 작성
@EnableFeignClients 을 작성하여 Feign Client 사용할 것임을 알려줌
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
import java.util.Arrays;
@Slf4j
@EnableCaching
@EnableFeignClients
@ServletComponentScan
@SpringBootApplication
@ComponentScan("com.poscoict.posmaster")
public class Application {
public static void main(String[] args) {
Arrays.stream(args)
.forEach(log::debug);
SpringApplication.run(Application.class, args);
}
}
인터페이스로 Client 작성
annotation을 통해 요청할 url을 설정함
import com.poscoict.posmaster.client.config.HeaderConfiguration;
import com.poscoict.posmaster.model.dto.ApiResponse;
import com.poscoict.posmaster.model.dto.shared.SharedDetailResponse;
import com.poscoict.posmaster.model.dto.shared.SharedPageResponse;
import com.poscoict.posmaster.model.dto.shared.SharedRequest;
import com.poscoict.posmaster.model.entity.App;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@FeignClient(name = "shared-api", url = "http://localhost:1323/api/v1", configuration = HeaderConfiguration.class)
public interface SharedClient {
@GetMapping("/pshm/list")
SharedPageResponse findSharedPageList(@RequestParam("offset") int offset, @RequestParam("limit") int limit);
@DeleteMapping("/pshm/delete")
ApiResponse deleteShared(@RequestParam("name") String name);
@PutMapping(value = "/pshm/update", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
ApiResponse modifyShared(@RequestParam("name") String name, @RequestParam("size") int size, @RequestParam("sender") String sender, @RequestParam("receiver") String receiver, @RequestParam("filedel") String filedel, @RequestPart(value = SharedRequest.MULTIPART_PARAM) MultipartFile file);
@PostMapping(value = "/pshm/write", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
ApiResponse modifyTagValue(@RequestParam("name") String tagName, @RequestParam("value") int value);
}
기본설정 값 및 Configuration
- feign 를 하다보면, 기본으로 설정되는 bean 들이 존재.
- Spring 을 사용하는 환경이라면, org.springframework.cloud.openfeign.FeignClientsConfiguration.class 에서 어떤 Bean 이 만들어지는지 확인 가능.
- default 설정을 override 하고 싶다면, configuration 에 설정된 값을 넣으면 됨
- 미설정 시 기본적으로 제공하는 설정정보로 사용
- configuration 을 이용해서 설정하기
- RequestIntercepor는 공통으로 사용하는 header를 추가하기위해 사용할 수 있음 (그 외 참고)
- RequestInterceptor는 interface이며 apply 메서드를 정의할 수 있음
- 원하는 feign client 에 configuration 에 만든 class를 설정.
- API endpoint 마다 사용하기 위해 여러 feign client를 만드는 경우 서로 다른 설정을 해야 함
package feign;
public interface RequestInterceptor {
void apply(RequestTemplate var1);
}
import com.poscoict.posmaster.model.SessionUser;
import feign.RequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
public class HeaderConfiguration {
@Bean
public RequestInterceptor requestInterceptor() {
return template -> {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes != null) {
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
if (request != null) {
if (request.getSession().getAttribute(SessionUser.TOKEN_KEY) != null) {
String token = (String) request.getSession().getAttribute(SessionUser.TOKEN_KEY);
template.header(HttpHeaders.AUTHORIZATION, "Bearer " + token);
}
}
}
};
}
}
- 공식 문서에서 제공하는 기본 설정 Bean
- @ConditionalOnMissingBean : 해당 Bean은 해당 옵션으로 사용하는 별도의 Bean이없을 때 적용되는 Default라는 의미
ex) Decoder feignDecoder, feignEncoder, feignLoggerFactory, feignContract, HystrixFeignConfiguration -
@Bean @ConditionalOnMissingBean public Decoder feignDecoder() { return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters))); }
- Configuration 사용 시 주의사항
-
Configuration class를 생성하다보면 습관적으로 @Configuration으로 설정하기 쉽다.
하지만 @Configuration으로 설정하게되면 되면 Spring bean으로 등록되어 모든 feign client 대상으로 적용이 된다.
따라서 모든 feign client에 적용되어야하는 설정은 @Configuration으로 적용되게 하고,
client 별로 적용되어야 하는 설정은 @FeignClient의 configuration attribute에 명시해서 추가해야한다.
참고로 같은 설정에 대해서는 @FeignClient의 configuration attribute의 설정으로 덮어씌워진다.
- @ConditionalOnMissingBean : 해당 Bean은 해당 옵션으로 사용하는 별도의 Bean이없을 때 적용되는 Default라는 의미
참고
Feign 적용(주의사항)
'Web > Front' 카테고리의 다른 글
[JavaScript]IP input mask (0) | 2021.10.28 |
---|---|
[Web]Custom Validator (0) | 2021.10.26 |
[Web]Freemarker문법 (0) | 2021.10.26 |
[JavaScript]JSON 형식의 문자열과 Encode 함수 (0) | 2021.10.25 |