Feign

November 03, 2022

Spring_MVC

목차

Feign

  • Feign은 Netflix에서 개발된 Http client binder이다.
  • Feign은 HTTP API 클라이언트를 단순화하는것을 목표로 합니다.
  • 실제로 interface를 만들고 annotation을 적용하는 간단한 방법으로 사용할 수 있음

    • Spring Data JPA에서 interface만 정의해서 쿼리를 실행하는 것과 유사

RestTemplate

기존의 RestTemplate를 사용하는 방법입니다. HttpEntity에 필요한 header와 body를 넣고 RestTemplate를 통해 URL과 HttpEntity를 넘겨서 ResponseEntity를 받는 구조입니다. 직관적이라 보고 이해기 쉽습니다.

package com.example.feign.feign.controller;

import com.example.feign.feign.dto.Dto;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class RestTemplateController {

    @GetMapping("/testRestTemplate")
    public ResponseEntity<Dto> testRestTemplate() {

        Dto reqDto = new Dto("Request RestTemplate");
        HttpHeaders headers = new HttpHeaders();
        HttpEntity<Dto> requestEntity = new HttpEntity<>(reqDto, headers);

        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> response = restTemplate.postForEntity("http://localhost:8080/targetService", requestEntity, String.class);

        System.out.println("response = " + response.getBody());

        return ResponseEntity.ok(new Dto());
    }

    @PostMapping("/targetService")
    public ResponseEntity<String> targetService(@RequestBody Dto dto) {
        System.out.println("dto = " + dto);
        return ResponseEntity.ok("Response RestTemplate");
    }
}

의존성

  • feign을 사용하기 위한 최소의 의존성 설정
  • spring cloud 버전은 spring boot 버전에 맞는 버전을 사용해야합니다.
  • https://spring.io/projects/spring-cloud 사이트에 확인하시면 됩니다.

    dependencies {
    ...  
    implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:3.1.4'
    implementation 'org.springframework.cloud:spring-cloud-starter-loadbalancer:3.1.4'
    ...
    
    //implementation 'io.github.openfeign:feign-httpclient:12.0'
    //implementation 'io.github.openfeign:feign-okhttp:12.0'
    }

Feign 사용하기

Application클래스에 Annotation EnableFeignClients 추가하기

root package에 있어야 하며 그렇지 않은 경우 basePackages or basePackageClass를 설정 해줘야 한다.

package com.example.feign.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);
	}
}

Annotation FeignClient을 사용하려면 okhttp or httpClient dependency를 추가 해주셔야 합니다.

value는 호출 하고자 하는 Eureka server에 인스턴스로 등록된 이름을 설정 해주면 된다.

FeignClient로 설정해주면 마치 자신의 API인 것처럼 정의가 가능합니다.

configuration은 OkHttpClient 빈 설정과, okHttpConnectionPoolFactory를 빈 설정을 해주고 필요한 interceptor를 설정하여 로그를 설정할 수 있음

configuration은 application.yml에서도 설정 할 수 있습니다.

url은 현재 프로젝트 url:port를 넣어주면 된다.

package com.example.feign.feign.Client;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient( value = "feign", url = "http://localhost:8080")
public interface ExampleClient {
    @PostMapping(value="/targetService")
    String sendMessage(@RequestParam("testValue") String testValue);
}

application.yml

feign:
  httpclient:
    config:

java configuration 설정법

@FeignClient( value = “feign”, url = ”http://localhost:8080”, configuration = {InternalFeignConfig.class})

@AutoConfigureAfter(FeignAutoConfiguration.class)
public class InternalFeignConfig {

    @Bean
    @ConditionalOnMissingBean({Client.class})
    public Client feignClient(okhttp3.OkHttpClient okHttpClient) {
        return new OkHttpClient(okHttpClient);
    }

    @Bean
    @ConditionalOnMissingBean({ConnectionPool.class})
    public ConnectionPool httpClientConnectionPool(FeignHttpClientProperties httpClientProperties, OkHttpClientConnectionPoolFactory okHttpClientConnectionPoolFactory) {
        return okHttpClientConnectionPoolFactory.create(httpClientProperties.getMaxConnections(), httpClientProperties.getTimeToLive(), httpClientProperties.getTimeToLiveUnit());
    }

    @Bean
    public okhttp3.OkHttpClient okHttpClient(OkHttpClientFactory okHttpClientFactory, ConnectionPool connectionPool, FeignHttpClientProperties feignHttpClientProperties) {
        return okHttpClientFactory.createBuilder(feignHttpClientProperties.isDisableSslValidation())
                .connectTimeout(30, TimeUnit.SECONDS)
                .followRedirects(feignHttpClientProperties.isFollowRedirects())
                .connectionPool(connectionPool)
                .addInterceptor(new InternalInterceptor())
                .build();
    }

}

테스트할 컨트롤러를 만든뒤 exampleClient를 주입시켜주고

exampleClient의 status 메서드를 호출하면 페인이 호출이 되고 원하는 응답으로 ksh is pretty가 받게 됩니다.

@RestController
public class AService {
	
    @Autowired
    private ExampleClient exampleClient;
 
    @PostMapping("/testFeign")
    public void testFeign(HttpServletResponse res) throws IOException {
        String result = exampleClient.sendMessage("ksh");
        System.out.println(result);
    }
}

RestTemplate으로 보내던 OpenFeign으로 보내던 받는곳은 동일하다.

A 서비스로부터 전달받은 ksh이라는 값이 testValue에 들어가있을것이고 그 응답을 is pretty로 붙혀줘서 다시 응답으로 보내준다.

@RestController
public class BService {
    @PostMapping(value = "/targetService")
    public String targetMethod(@RequestParam("testValue") String testValue){
        return testValue + " is pretty";
    }
}

장점

  • 장점

    1. Feign을 사용하게 되면 RestTemplate보다 Rest API 사용하는데 필요한 설정이 간편해집니다.(이러한 편한점으로 인해 비지니스 로직에 더 집중할 수 있음)
    2. 다른 라이브러리에 비하면, 학습의 어렴움이 거의 없음

참고 자료


Written by @Sihwan Kim

넥스트이노베이션의 기술, 문화, 뉴스, 행사 등 최신 소식 및 넥스트이노베이션이 겪은 다양한 경험을 공유합니다.