목차
Spring Cloud OpenFeign은 스프링에서 제공하는 오픈소스 HTTP Client 입니다. 애플리케이션 내부적으로 다른 시스템과 HTTP 통신을 해야 할 때 간편하게 사용할 수 있습니다. OpenFeign 예제로 사용법을 간단하게 배워 봅시다.
간단한 Client Application과 Server Application을 만들어서 테스트합니다. 그런데 서로 다른 애플리케이션이 통신하는 것이므로 Client Application 의 FeignClient 리턴 타입과 Server Application의 Controller 리턴 타입은 다를 수 있습니다. 이러한 상황에서 어떻게 동작할 지 궁금하지 않나요? OpenFeign을 사용할 때 알아둬야 할 내용이라고 생각합니다. 궁금증을 해소하기 위해 테스트 했던 내용을 공유합니다.
Client측 Application
java 17, Spring Boot 3.1.3 버전을 사용했습니다. Spring Cloud의 버전은 2022.0.4 입니다.
사용하는 스프링 부트의 버전에 따라서 호환되는 Spring Cloud 버전이 다를 수 있으니 주의하세요.
(https://spring.io/projects/spring-cloud 이 페이지의 Table 1.에서 확인하실 수 있습니다.)
간단하게 Controller를 만들어서 테스트 해볼 예정이므로 spring-boot-starter-web, openfeign, lombok 의존성을 추가했습니다.
build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.3'
id 'io.spring.dependency-management' version '1.1.3'
}
group = 'com.greenneuron'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
ext {
set('springCloudVersion', "2022.0.4")
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
tasks.named('test') {
useJUnitPlatform()
}
Main Class
FeginClient를 스캔할 수 있게 하기 위해서 FeignClient가 위치할 패키지를 지정합니다.
package com.greenneuron.openfeignclient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients(basePackages = "com.greenneuron.openfeignclient")
public class OpenFeignClientApplication {
public static void main(String[] args) {
SpringApplication.run(OpenFeignClientApplication.class, args);
}
}
FeignClient
FeignClient 인터페이스를 만들고, 요청을 보낼 서버의 URL을 지정합니다. (URL을 동적으로 할 수도 있으나 여기서는 고정합니다.) 구현체를 자동으로 만들어 Bean으로 등록해주기 때문에 Interface만 작성하면 됩니다. OpenFeignClient
구현체는 @FeignClient
에 지정된 url
로 GET /echo
요청을 보내게 되고 WordDto
로 응답을 받게 됩니다. value
는 스프링에 자동으로 등록될 Bean의 이름이 됩니다.
package com.greenneuron.openfeignclient;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@FeignClient(value = "echo", url = "http://127.0.0.1:8080/")
public interface EchoClient {
@ResponseBody
@GetMapping("/echo")
WordDto echo(@RequestParam("word") String word);
}
DTO
DTO는 데이터를 주고 받을 때 사용하는 객체입니다.
package com.greenneuron.openfeignclient;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class WordDto {
private String word;
private String who;
}
멤버 변수의 이름을 눈 여겨 봐 주세요. 서버로부터 DTO를 응답 받았을 때, 리턴 타입으로 지정한 DTO의 멤버 변수 중 이름이 일치하는 멤버 변수에 한하여 값이 세팅 됩니다. 멤버 변수의 이름만 일치하면 동일한 DTO가 아니어도 값이 세팅 됩니다.
Controller
단순하게 POST /echo/hello-world
요청이 들어오면 Hello World!
를 출력하는 서블릿을 등록합니다. 이 때 위에서 만든 FeignClient를 사용합니다.
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RequiredArgsConstructor
@RestController
public class OpenFeignTestController {
private final EchoClient echoClient;
@PostMapping("/echo/hello-world")
public String run() {
WordDto echo1 = echoClient.echo("Hello,");
log.info(echo1.toString());
WordDto echo2 = echoClient.echo("World!");
log.info(echo2.toString());
String result = echo1.getWord() + " " + echo2.getWord();
log.info(result);
return result;
}
}
Server측 Application
요청으로 들어온 word를 그대로 응답하는 Get /echo?word={word}
REST API를 제공합니다.
응답 JSON
{
"word" : "{word}",
"other" : "abc"
}
필드 이름이 다른 경우 어떻게 동작하는지 확인하기 위한 목적으로, 항상 “other” : “abc” 을 응답합니다.
build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.3'
id 'io.spring.dependency-management' version '1.1.3'
}
group = 'com.greenneuron'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
Main Class
package com.greenneuron.echoservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class EchoServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EchoServiceApplication.class, args);
}
}
Controller
package com.greenneuron.echoservice;
import lombok.Getter;
import lombok.Setter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class EchoController {
@GetMapping("/echo")
public OtherWordDto openFeign(@RequestParam("word") String word) {
return new OtherWordDto(word, "abc");
}
@Getter
@Setter
static class OtherWordDto {
private final String word;
private final String other;
public OtherWordDto(String word, String other) {
this.word = word;
this.other = other;
}
}
}
테스트 결과
리턴 타입이 달라도 멤버 변수의 이름이 동일하면 값을 응답 받을 수 있었습니다. 멤버 변수의 이름이 다르면 값을 응답 받지 못합니다.
HTTP 요청/응답
Console log
- DTO에 값을 세팅할 때 field의 이름을 기준으로 매핑
who
field에"abc"
가 세팅 되지 않고null
인 것을 확인할 수 있음
2023-10-13T01:19:15.751+09:00 INFO 22276 --- [nio-8079-exec-2] c.g.o.OpenFeignTestController : WordDto(word=Hello,, who=null)
2023-10-13T01:19:15.754+09:00 INFO 22276 --- [nio-8079-exec-2] c.g.o.OpenFeignTestController : WordDto(word=World!, who=null)
2023-10-13T01:19:15.755+09:00 INFO 22276 --- [nio-8079-exec-2] c.g.o.OpenFeignTestController : Hello, World!