ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring Cloud OpenFeign, 그리고 SSL
    기록해야 기억한다/Spring 2020. 12. 29. 00:05

    OpenFeign (github.com/OpenFeign/feign)

    Feign 은 선언적 Web Service Client 인 오픈소스이다. 이를 이용해 우리가 Spring 에서 Service 를 DI 를 통해 호출하여 사용하는 것처럼 웹서비스 Client 를 사용할 수 있게 도와준다. 

     

    Feign 은 Interface 를 만들고 annotation 을 추가하는것으로 쉽게 사용할 수 있고, encoder, decoder 를 플러그형으로 지원한다.

     

    Spring Cloud OpenFeign

    Spring Cloud는 Spring MVC annotation 및 Spring Web에서 기본적으로 사용되는 동일한 HttpMessageConverters를 사용하기위한 지원을 추가하고 Eureka, Spring Cloud LoadBalancer 를 통합하여 Feign 을 사용할 때 부하 분산 된 http 클라이언트를 제공하는 역할을 한다. 물론 Eureka, LoadBalancer 등을 사용하지 않아도 된다.

     

    Spring boot 에서의 사용 선언

    maven/gradle 에서 spring-cloud-starter-openfeign 선언을 통해 사용할 수 있으며 spring boot 에서의 규칙과 같이 @Enable annotation 을 통해 사용가능하도록 ON 한다.

    아래의 코드들은 reference 문서를 이용하거나 간략히 수정한 내용입니다.
    @SpringBootApplication
    @EnableFeignClients
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    
    }

    StoreClient.java

    @FeignClient("stores")
    public interface StoreClient {
        @RequestMapping(method = RequestMethod.GET, value = "/stores")
        List<Store> getStores();
    
        @RequestMapping(method = RequestMethod.GET, value = "/stores")
        Page<Store> getStores(Pageable pageable);
    
        // or
        @PostMapping("/stores/{storeId}", consumes = "application/json")
        Store update(@PathVariable("storeId") Long storeId, Store store);
    }

    @FeignClient 는 name, url, configuration 등을 선언할 수 있고, 이 중 name 은 LoadBalancer 클라이언트의 이름으로 사용됩니다. url 은 절대값이나 hostname 만을 사용하여 URL을 지정할 수 있고 Placeholders 를 지원한다.

     

    Feign 기본 값의 재정의(Overriding)

    Spring Cloud는 FeignClientsConfiguration을 사용하여 각 명명 된 클라이언트에 대한 요구에 따라 ApplicationContext로 새로운 앙상블을 생성하고, @FeignClient 어노테이션의 contextId 속성을 사용하여 해당 앙상블의 이름(Bean name)을 대체 할 수 있다.Configuration part 들은 아래와 같이 구성할 수 있고 해당 속성을 재정의하면 기존 구성을 대체한다.

    • feign.Decoder
    • feign.Encoder
    • feign.Contract
    @FeignClient(name = "stores", configuration = FooConfiguration.class)
    public interface StoreClient {
        //..
    }
    @FeignClient 의 configuration 속성으로 지정된 class 는 Spring Component 인 @Configuration 으로 선언할 필요가 없다. 만약 지정된 경우는 해당 클래스에서 선언된 part 들이 기본 구성이 된다. 만약 선언한다면 @ComponentScan 의 패키지 밖에 선언하거나, 명시적으로 exclude 시켜서 제외할 수 있다.
    url 속성을 사용할때는 꼭 name 속성이 필요하다.

     

    Spring Cloud OpenFeign 은 기본적으로 다음의 Bean 들을 제공한다.

    • Bean 형태 : bean 이름 : Class 이름
    • Decoder : feignDecoder : ResponseEntityDecoder(SpringDecoder 를 감싼)
    • Encoder : feignEncoder : SpringEncoder
    • Logger : feignLogger : Slf4jLogger
    • Contract : feignContract : SpringMvcContract
    • Feign.Builder : feignBuilder : HystrixFeign.Builder
    • Client : feignClient : Spring Cloud LoadBalancer 가 classpath 에 있으면 FeignBlockingLoadBalancerClient, 없으면 기본 feign client 가 사용된다.

    위의 Bean 들은 @Configuration 을 통해 구성할 수 있지만 properties(feign.~~) 을 통해서도 가능하며, @Configuration 과 함께 선언되어 있으면 properties 파일이 우선됩니다.

    #application.yml
    feign:
      client:
        config:
          feignName:
            connectTimeout: 5000
            readTimeout: 5000
            loggerLevel: full
            errorDecoder: com.example.SimpleErrorDecoder
            retryer: com.example.SimpleRetryer
            requestInterceptors:
              - com.example.FooRequestInterceptor
              - com.example.BarRequestInterceptor
            decode404: false
            encoder: com.example.SimpleEncoder
            decoder: com.example.SimpleDecoder
            contract: com.example.SimpleContract

    OkHttpClient, ApacheHttpClient 를 이용해 feign client 를 사용하려면 feign.[client].enabled 속성을 설정(true)하고 classpath 에 추가하면 사용할 수 있다. Apache 를 사용할 경우 org.apache.http.impl.client.CloseableHttpClient, OK HTTP 를 사용할 경우 okhttp3.OkHttpClient 를 사용하며 bean을 제공하여 HTTP Client 를 customize 할 수 있다.

     

    경우에 따라 Feign.Builder API 를 통해 Feign 클라이언트를 사용자정의 형식으로 생성할 수 있다.  

     

    Feign 에서의 SSL - ignore Cerification

    기본적으로 @FeignClient 의 url 속성에 프로토콜을 명시하지 않으면 http 로 요청을 생성하고 필요한 경우 명시적으로 프로토콜을 선언하면 해당 프로토콜로 생성된다.

     

    HttpClient, HttpUrlConnection 등의 클래스들을 통해 SSL 을 사용할 때 테스트를 위해서? 혹은 환경적인 요인으로 인해서건 SSL 을 무시해야 할 경우가 있고, Feign 에서의 그 방법을 설명한다.

     

    기본적으로 @FeignClient 의 configuration 을 통해 구성을 할 수 있고 해당 구성에서 feign.Client(feignClient) 을 재정의 해서 해결 할 수 있다.

    public class SslCertificationIgnoreConfiguration {
        private SSLSocketFactory sslContextFactory() throws NoSuchAlgorithmException, KeyManagementException {
            SSLContext ssl_ctx = SSLContext.getInstance("TLS");
            TrustManager[] certs = new TrustManager[]{
                    new X509TrustManager() {
                        public X509Certificate[] getAcceptedIssuers() {
                            return new X509Certificate[]{};
                        }
    
                        public void checkClientTrusted(X509Certificate[] certs, String t) {
                        }
    
                        public void checkServerTrusted(X509Certificate[] certs, String t) {
                        }
                    }};
            ssl_ctx.init(null, certs, new SecureRandom());
            return ssl_ctx.getSocketFactory();
        }
    
        @Bean
        public feign.Client client() throws KeyManagementException, NoSuchAlgorithmException {
            return new Client.Default(sslContextFactory(), (hostname, session) -> true);
        }
    }
    

     

    feign.Client 선언을 통해 Client 빈이 재정의 되며 해당 client 는 재정의된 TrustManager, HostnameVerifier 를 통해 통과되어 진행한다. 단, 해당방법은 인증서 문제등으로 해결할 수 없는 경우에만 사용하는게 바람직하다.

    반응형
    LIST

    댓글

Designed by Tistory.