hanseom 2022. 7. 23. 07:22
반응형

Overview

  해당 글에서는 RestTemplate보다 사용이 간단하고 직관적인 FeignClient를 적용해 보겠습니다. FeignClient는 HTTP Client로 REST Call을 추상화 한 Spring Cloud Netflix 라이브러리입니다.

 

FeignClient 적용

의존성 추가

implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'

@EnableFeignClients 적용

package com.example.userservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class UserServiceApplication {

  public static void main(String[] args) {
    SpringApplication.run(UserServiceApplication.class, args);
  }

  @Bean
  public RestTemplate getRestTemplate() {
    return new RestTemplate();
  }
}

호출하려는 HTTP Endpoint에 대한 Interface 생성 (url은 config 파일로 관리합니다.)

package com.example.userservice.client;

import com.example.userservice.RestTemplateResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name = "jsonPlaceHolderClient", url = "https://jsonplaceholder.typicode.com/")
public interface JsonPlaceHolderClient {

  @GetMapping("/todos/{id}")
  RestTemplateResponse getTodos(@PathVariable String id);
}

FeignClient 사용

  JsonPlaceHolderClient를 생성자 주입 받아 getTodos 메서드를 호출합니다. 단순 확인을 위한 호출로 Controller 단에서 수행하며, 이전 글의 RestTemplateResponse를 그대로 적용합니다. 

package com.example.userservice;

import com.example.userservice.client.JsonPlaceHolderClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/")
public class UserController {
  /*** 생략 ***/

  JsonPlaceHolderClient jsonPlaceHolderClient;

  @Autowired
  public UserController(Environment env, RestTemplate restTemplate,
      JsonPlaceHolderClient jsonPlaceHolderClient) {
  	/*** 생략 ***/
    this.jsonPlaceHolderClient = jsonPlaceHolderClient;
  }

  @GetMapping("/welcome")
  public String welcome() {
    String configMessage = env.getProperty("greeting.message");

    /* RestTemplate */
//    System.out.println(restTemplate.getForObject("https://jsonplaceholder.typicode.com/todos/1",
//        RestTemplateResponse.class));
//    restTemplate.getForObject("url", Object.class);
//    restTemplate.postForObject("url", "Request.class", Object.class);
//    restTemplate.put("url", "Request.class");
//    restTemplate.delete("url");

    /* FeignClient */
    RestTemplateResponse response = jsonPlaceHolderClient.getTodos("1");
    System.out.println(response);

    return "Hello, User-service: " + configMessage;
  }
}

 

FeignClient Logger

application.yml (com.example.userservice.client는 package 경로입니다.)

logging:
  level:
    com.example.userservice.client: DEBUG

@Bean 등록

package com.example.userservice;

import feign.Logger;
/*** 생략 ***/

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class UserServiceApplication {
  /*** 생략 ***/

  @Bean
  public Logger.Level feignLoggerLevel() {
    return Logger.Level.FULL;
  }
}

서버 재기동 후 호출 시 아래와 같은 로그를 볼 수 있습니다.

 

FeignClient Exception 처리

ErrorDecoder 구현

  FeignClient에서 발생하는 Exception을 한 곳에서 처리할 수 있습니다. @Component로 @Bean을 등록하고 ErrorDecoder를 상속받아 decode 메서드를 재정의하면 됩니다. 상태코드에 따라 적절한 처리를 해주면 됩니다.

package com.example.userservice.client;

import feign.Response;
import feign.codec.ErrorDecoder;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ResponseStatusException;

@Component
public class FeignErrorDecoder implements ErrorDecoder {

  @Override
  public Exception decode(String methodKey, Response response) {
    switch (response.status()) {
      case 400:
        break;
      case 404:
        if (methodKey.contains("getTodos")) {
          return new ResponseStatusException(HttpStatus.valueOf(response.status()),
              "getTodos Bad Request Exception!!!");
        }
        break;
      default:
        return new Exception(response.reason());
    }

    return null;
  }
}

 

 

 

[참고 정보]

반응형