본문 바로가기

Backend Development/Spring boot

[Spring boot] RestTemplate 으로 http 통신하기

Spring 에서 제공하는 http client로는 대표적으로 RestTemplate이 있다. 이 RestTemplate으로 http 요청을 날리게되면 기본적으로 그때마다 connection을 맺고 응답을 받으면 끊게된다.

 

Spring 에서 제공하는 RestTemplate은 직접 http 요청을 하는 역할을 수행하지않는다. 직접 수행하는 클래스를 한번 래핑한 어댑터 역할을 하는 클래스이다. 기본적으로는 jdk에서 제공하는 HttpUrlConnection 클래스를 이용한다.

 

 기본적인 예제를 아래와 같이 만들어보고 간단한 Get 메소드를 호출해본다.

 

예제 #1

@Service
public class HttpUtil<K, T> {

    private final ObjectMapper objectMapper = new ObjectMapper();

    public T getForObject(String apiKey, String url, MultiValueMap<String, String> queryParams, Class<T> responseType) {

        T response;

        try {

            UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromHttpUrl(url);
            urlBuilder.queryParams(queryParams);

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(new MediaType("application", "json", StandardCharsets.UTF_8));
            
            HttpEntity<String> entity = new HttpEntity<>(headers);
            RestTemplate restTemplate = new RestTemplateBuilder().setReadTimeout(Duration.ofMillis(5000)).build();

            ResponseEntity<String> respEntityStr = restTemplate.exchange(urlBuilder.build().toUri(), HttpMethod.GET, entity, String.class);

            if (responseType == null) {
                response = (T) objectMapper.readValue(respEntityStr.getBody(), Map.class);
            } else {
                response = objectMapper.readValue(respEntityStr.getBody(), responseType);
            }

        } catch (Exception e) {
            throw new BizException(EnumException.CMM00.getMessage(), EnumException.CMM00.getCode());
        }

        return response;
    }
}

 

테스트 호출 예제

    @Test
    public void HttpUtilTest() throws Exception {

        for (int i = 0; i < 1000; ++i) {
            try {
                Object response = httpUtil.getForObject("test", "https://e1.emxdgt.com/put?d=d53&uid=k-8kmphgEOGKus3r36HMzG9O8usvByN-JbJTjQBQ", null, null);

            } catch (Exception e) {

            }

            Thread.sleep(1000);
        }
    }

 

응답 로그

2023-04-29T08:33:43.928+09:00 DEBUG 22276 --- [           main] o.s.web.client.RestTemplate              : HTTP GET https://e1.emxdgt.com/put?d=d53&uid=k-8kmphgEOGKus3r36HMzG9O8usvByN-JbJTjQBQ
2023-04-29T08:33:43.931+09:00 DEBUG 22276 --- [           main] o.s.web.client.RestTemplate              : Accept=[text/plain, application/json, application/*+json, */*]
2023-04-29T08:33:43.939+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.i.classic.InternalHttpClient   : ex-0000000001 preparing request execution
2023-04-29T08:33:43.950+09:00 DEBUG 22276 --- [           main] o.a.h.c.http.impl.classic.ProtocolExec   : ex-0000000001 target auth state: UNCHALLENGED
2023-04-29T08:33:43.951+09:00 DEBUG 22276 --- [           main] o.a.h.c.http.impl.classic.ProtocolExec   : ex-0000000001 proxy auth state: UNCHALLENGED
2023-04-29T08:33:43.951+09:00 DEBUG 22276 --- [           main] o.a.h.c.http.impl.classic.ConnectExec    : ex-0000000001 acquiring connection with route {s}->https://e1.emxdgt.com:443
2023-04-29T08:33:43.952+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.i.classic.InternalHttpClient   : ex-0000000001 acquiring endpoint (3 MINUTES)
2023-04-29T08:33:43.953+09:00 DEBUG 22276 --- [           main] h.i.i.PoolingHttpClientConnectionManager : ex-0000000001 endpoint lease request (3 MINUTES) [route: {s}->https://e1.emxdgt.com:443][total available: 0; route allocated: 0 of 5; total allocated: 0 of 25]
2023-04-29T08:33:43.957+09:00 DEBUG 22276 --- [           main] h.i.i.PoolingHttpClientConnectionManager : ex-0000000001 endpoint leased [route: {s}->https://e1.emxdgt.com:443][total available: 0; route allocated: 1 of 5; total allocated: 1 of 25]
2023-04-29T08:33:43.965+09:00 DEBUG 22276 --- [           main] h.i.i.PoolingHttpClientConnectionManager : ex-0000000001 acquired ep-0000000001
2023-04-29T08:33:43.966+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.i.classic.InternalHttpClient   : ex-0000000001 acquired endpoint ep-0000000001
2023-04-29T08:33:43.966+09:00 DEBUG 22276 --- [           main] o.a.h.c.http.impl.classic.ConnectExec    : ex-0000000001 opening connection {s}->https://e1.emxdgt.com:443
2023-04-29T08:33:43.966+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.i.classic.InternalHttpClient   : ep-0000000001 connecting endpoint (null)
2023-04-29T08:33:43.967+09:00 DEBUG 22276 --- [           main] h.i.i.PoolingHttpClientConnectionManager : ep-0000000001 connecting endpoint to https://e1.emxdgt.com:443 (3 MINUTES)
2023-04-29T08:33:43.967+09:00 DEBUG 22276 --- [           main] .i.i.DefaultHttpClientConnectionOperator : e1.emxdgt.com resolving remote address
2023-04-29T08:33:43.979+09:00 DEBUG 22276 --- [           main] .i.i.DefaultHttpClientConnectionOperator : e1.emxdgt.com resolved to [e1.emxdgt.com/18.204.165.198, e1.emxdgt.com/54.209.108.126, e1.emxdgt.com/34.202.136.134, e1.emxdgt.com/18.235.95.163, e1.emxdgt.com/35.173.40.160, e1.emxdgt.com/54.174.207.255, e1.emxdgt.com/34.205.128.40, e1.emxdgt.com/107.23.108.9]
2023-04-29T08:33:43.982+09:00 DEBUG 22276 --- [           main] .i.i.DefaultHttpClientConnectionOperator : e1.emxdgt.com:443 connecting null->e1.emxdgt.com/18.204.165.198:443 (3 MINUTES)
2023-04-29T08:33:43.982+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.s.SSLConnectionSocketFactory   : Connecting socket to e1.emxdgt.com/18.204.165.198:443 with timeout 3 MINUTES
2023-04-29T08:33:44.214+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.s.SSLConnectionSocketFactory   : Enabled protocols: [TLSv1.3, TLSv1.2]
2023-04-29T08:33:44.215+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.s.SSLConnectionSocketFactory   : Enabled cipher suites: [TLS_AES_256_GCM_SHA384, TLS_AES_128_GCM_SHA256, TLS_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
2023-04-29T08:33:44.215+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.s.SSLConnectionSocketFactory   : Starting handshake (null)
2023-04-29T08:33:44.443+09:00 DEBUG 22276 --- [           main] jdk.event.security                       : X509Certificate: Alg:SHA256withRSA, Serial:6f5ba4c51b10145d754ccbf058c9149, Subject:CN=*.emxdgt.com, Issuer:CN=Amazon RSA 2048 M01, O=Amazon, C=US, Key type:RSA, Length:2048, Cert Id:-511862481, Valid from:23. 3. 1. 오전 9:00, Valid until:23. 7. 3. 오전 8:59
2023-04-29T08:33:44.443+09:00 DEBUG 22276 --- [           main] jdk.event.security                       : X509Certificate: Alg:SHA256withRSA, Serial:77312380b9d6688a33b1ed9bf9ccda68e0e0f, Subject:CN=Amazon RSA 2048 M01, O=Amazon, C=US, Issuer:CN=Amazon Root CA 1, O=Amazon, C=US, Key type:RSA, Length:2048, Cert Id:-1856842780, Valid from:22. 8. 24. 오전 7:21, Valid until:30. 8. 24. 오전 7:21
2023-04-29T08:33:44.444+09:00 DEBUG 22276 --- [           main] jdk.event.security                       : X509Certificate: Alg:SHA256withRSA, Serial:67f944a2a27cdf3fac2ae2b01f908eeb9c4c6, Subject:CN=Amazon Root CA 1, O=Amazon, C=US, Issuer:CN=Starfield Services Root Certificate Authority - G2, O="Starfield Technologies, Inc.", L=Scottsdale, ST=Arizona, C=US, Key type:RSA, Length:2048, Cert Id:668791387, Valid from:15. 5. 25. 오후 9:00, Valid until:37. 12. 31. 오전 10:00
2023-04-29T08:33:44.444+09:00 DEBUG 22276 --- [           main] jdk.event.security                       : X509Certificate: Alg:SHA256withRSA, Serial:a70e4a4c3482b77f, Subject:CN=Starfield Services Root Certificate Authority - G2, O="Starfield Technologies, Inc.", L=Scottsdale, ST=Arizona, C=US, Issuer:OU=Starfield Class 2 Certification Authority, O="Starfield Technologies, Inc.", C=US, Key type:RSA, Length:2048, Cert Id:1766010387, Valid from:09. 9. 2. 오전 9:00, Valid until:34. 6. 29. 오전 2:39
2023-04-29T08:33:44.463+09:00 DEBUG 22276 --- [           main] jdk.event.security                       : ValidationChain: -1472444962, -1856842780, -511862481
2023-04-29T08:33:44.674+09:00 DEBUG 22276 --- [           main] jdk.event.security                       :  TLSHandshake: e1.emxdgt.com:443, TLSv1.2, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, -511862481
2023-04-29T08:33:44.674+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.s.SSLConnectionSocketFactory   : Secure session established
2023-04-29T08:33:44.674+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.s.SSLConnectionSocketFactory   :  negotiated protocol: TLSv1.2
2023-04-29T08:33:44.675+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.s.SSLConnectionSocketFactory   :  negotiated cipher suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
2023-04-29T08:33:44.675+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.s.SSLConnectionSocketFactory   :  peer principal: CN=*.emxdgt.com
2023-04-29T08:33:44.675+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.s.SSLConnectionSocketFactory   :  peer alternative names: [*.emxdgt.com, emxdgt.com]
2023-04-29T08:33:44.675+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.s.SSLConnectionSocketFactory   :  issuer principal: CN=Amazon RSA 2048 M01, O=Amazon, C=US
2023-04-29T08:33:44.676+09:00 DEBUG 22276 --- [           main] h.i.i.DefaultManagedHttpClientConnection : http-outgoing-0 set socket timeout to 5000 MILLISECONDS
2023-04-29T08:33:44.676+09:00 DEBUG 22276 --- [           main] .i.i.DefaultHttpClientConnectionOperator : e1.emxdgt.com:443 connected null->e1.emxdgt.com/18.204.165.198:443 as http-outgoing-0
2023-04-29T08:33:44.676+09:00 DEBUG 22276 --- [           main] h.i.i.PoolingHttpClientConnectionManager : ep-0000000001 connected http-outgoing-0
2023-04-29T08:33:44.676+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.i.classic.InternalHttpClient   : ep-0000000001 endpoint connected
2023-04-29T08:33:44.677+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.impl.classic.MainClientExec    : ex-0000000001 executing GET /put?d=d53&uid=k-8kmphgEOGKus3r36HMzG9O8usvByN-JbJTjQBQ HTTP/1.1
2023-04-29T08:33:44.677+09:00 DEBUG 22276 --- [           main] o.a.h.c.http.protocol.RequestAddCookies  : ex-0000000001 Cookie spec selected: strict
2023-04-29T08:33:44.682+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.i.classic.InternalHttpClient   : ep-0000000001 start execution ex-0000000001
2023-04-29T08:33:44.682+09:00 DEBUG 22276 --- [           main] h.i.i.PoolingHttpClientConnectionManager : ep-0000000001 executing exchange ex-0000000001 over http-outgoing-0
2023-04-29T08:33:44.683+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.headers       : http-outgoing-0 >> GET /put?d=d53&uid=k-8kmphgEOGKus3r36HMzG9O8usvByN-JbJTjQBQ HTTP/1.1
2023-04-29T08:33:44.683+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.headers       : http-outgoing-0 >> Accept: text/plain, application/json, application/*+json, */*
2023-04-29T08:33:44.683+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.headers       : http-outgoing-0 >> Content-Type: application/json;charset=UTF-8
2023-04-29T08:33:44.683+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.headers       : http-outgoing-0 >> x-el-key: test
2023-04-29T08:33:44.683+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.headers       : http-outgoing-0 >> Accept-Encoding: gzip, x-gzip, deflate
2023-04-29T08:33:44.683+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.headers       : http-outgoing-0 >> Content-Length: 0
2023-04-29T08:33:44.683+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.headers       : http-outgoing-0 >> Host: e1.emxdgt.com
2023-04-29T08:33:44.683+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.headers       : http-outgoing-0 >> Connection: keep-alive
2023-04-29T08:33:44.683+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.headers       : http-outgoing-0 >> User-Agent: Apache-HttpClient/5.2.1 (Java/17.0.6)
2023-04-29T08:33:44.684+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 >> "GET /put?d=d53&uid=k-8kmphgEOGKus3r36HMzG9O8usvByN-JbJTjQBQ HTTP/1.1[\r][\n]"
2023-04-29T08:33:44.684+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 >> "Accept: text/plain, application/json, application/*+json, */*[\r][\n]"
2023-04-29T08:33:44.684+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 >> "Content-Type: application/json;charset=UTF-8[\r][\n]"
2023-04-29T08:33:44.684+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 >> "x-el-key: test[\r][\n]"
2023-04-29T08:33:44.684+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 >> "Accept-Encoding: gzip, x-gzip, deflate[\r][\n]"
2023-04-29T08:33:44.684+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 >> "Content-Length: 0[\r][\n]"
2023-04-29T08:33:44.684+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 >> "Host: e1.emxdgt.com[\r][\n]"
2023-04-29T08:33:44.684+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 >> "Connection: keep-alive[\r][\n]"
2023-04-29T08:33:44.684+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 >> "User-Agent: Apache-HttpClient/5.2.1 (Java/17.0.6)[\r][\n]"
2023-04-29T08:33:44.684+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 >> "[\r][\n]"
2023-04-29T08:33:44.880+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 << "HTTP/1.1 200 OK[\r][\n]"
2023-04-29T08:33:44.881+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 << "Server: awselb/2.0[\r][\n]"
2023-04-29T08:33:44.881+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 << "Date: Fri, 28 Apr 2023 23:33:45 GMT[\r][\n]"
2023-04-29T08:33:44.881+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 << "Content-Type: text/plain; charset=utf-8[\r][\n]"
2023-04-29T08:33:44.881+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 << "Content-Length: 0[\r][\n]"
2023-04-29T08:33:44.881+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 << "Connection: keep-alive[\r][\n]"
2023-04-29T08:33:44.881+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.wire          : http-outgoing-0 << "[\r][\n]"
2023-04-29T08:33:44.883+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.headers       : http-outgoing-0 << HTTP/1.1 200 OK
2023-04-29T08:33:44.883+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.headers       : http-outgoing-0 << Server: awselb/2.0
2023-04-29T08:33:44.883+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.headers       : http-outgoing-0 << Date: Fri, 28 Apr 2023 23:33:45 GMT
2023-04-29T08:33:44.883+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.headers       : http-outgoing-0 << Content-Type: text/plain; charset=utf-8
2023-04-29T08:33:44.883+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.headers       : http-outgoing-0 << Content-Length: 0
2023-04-29T08:33:44.883+09:00 DEBUG 22276 --- [           main] org.apache.hc.client5.http.headers       : http-outgoing-0 << Connection: keep-alive
2023-04-29T08:33:44.884+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.impl.classic.MainClientExec    : ex-0000000001 connection can be kept alive for 3 MINUTES
2023-04-29T08:33:44.884+09:00 DEBUG 22276 --- [           main] o.a.h.c.h.i.classic.InternalHttpClient   : ep-0000000001 releasing valid endpoint
2023-04-29T08:33:44.885+09:00 DEBUG 22276 --- [           main] h.i.i.PoolingHttpClientConnectionManager : ep-0000000001 releasing endpoint
2023-04-29T08:33:44.885+09:00 DEBUG 22276 --- [           main] h.i.i.PoolingHttpClientConnectionManager : ep-0000000001 connection http-outgoing-0 can be kept alive for 3 MINUTES
2023-04-29T08:33:44.885+09:00 DEBUG 22276 --- [           main] h.i.i.PoolingHttpClientConnectionManager : ep-0000000001 connection released [route: {s}->https://e1.emxdgt.com:443][total available: 1; route allocated: 1 of 5; total allocated: 1 of 25]
2023-04-29T08:33:44.887+09:00 DEBUG 22276 --- [           main] o.s.web.client.RestTemplate              : Response 200 OK
2023-04-29T08:33:45.893+09:00 DEBUG 22276 --- [           main] o.s.web.client.RestTemplate              : HTTP GET https://e1.emxdgt.com/put?d=d53&uid=k-8kmphgEOGKus3r36HMzG9O8usvByN-JbJTjQBQ
2023-04-29T08:33:45.893+09:00 DEBUG 22276 --- [           main] o.s.web.client.RestTemplate              : Accept=[text/plain, application/json, application/*+json, */*]

 

간단한 설정으로 Get 메소드를 호출하고 응답까지 확인을 해봤다.

 

그러나 위 설정은 그때 그때 요청이 있을때마다 객체를 생성해서 커넥션을 시도 하는데 이럴 경우 Connection pool을 사용하지 않고 매번 새로운 커넥션을 생성하게 된다. 당연히 중복 포트가 계속 생성되고 client, server모두 낭비가 될것이다. 때에 따라서는 close 처리가 제대로 안되어서 close_wait상태의 커넥션 들이 좀비처럼 늘어나게 되기도 한다.

 

이럴 경우 전역으로 rest template connection pool 설정을 하고 Bean으로 주입 받으면 단독 conneciton 생성이 아닌 connection pool 내에서 오퍼레이션을 하므로 효율적인 네트웍 환경을 갖출 수 있게 된다.

 

RestTemplateConfig 설정을 위해 아래 최신 httpclient5 라이브러리를 다운 받는다.

<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
    <version>5.2.1</version>
</dependency>

 

그리고 RestTemplate Configuration을 만들고 factory 설정을 restTempalte 생성시 주입한다.

import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

    @Bean
    HttpClient httpClient() {
        return HttpClientBuilder.create()
                .setConnectionManager(PoolingHttpClientConnectionManagerBuilder.create()
                        .setMaxConnPerRoute(100)
                        .setMaxConnTotal(300)
                        .build())
                .build();
    }

    @Bean
    HttpComponentsClientHttpRequestFactory factory(HttpClient httpClient) {
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setConnectTimeout(3000);
        factory.setHttpClient(httpClient);

        return factory;
    }

    @Bean
    RestTemplate restTemplate(HttpComponentsClientHttpRequestFactory factory) {
        return new RestTemplate(factory);
    }
}

 

아까와 다르게 restTemplate을 @Autowired로 주입 받는다. 

이렇게 되면 전역 factory 설정으로 생성한 connection pool을 가지고 그안에서 통신을 수행하게 된다.

 

예제 #2

@Service
public class HttpUtil<K, T> {

    @Autowired
    private RestTemplate restTemplate;

    private final ObjectMapper objectMapper = new ObjectMapper();

    public T getForObject(String apiKey, String url, MultiValueMap<String, String> queryParams, Class<T> responseType) {

        T response;

        try {

            UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromHttpUrl(url);
            urlBuilder.queryParams(queryParams);

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(new MediaType("application", "json", StandardCharsets.UTF_8));

            HttpEntity<String> entity = new HttpEntity<>(headers);

            ResponseEntity<String> respEntityStr = restTemplate.exchange(urlBuilder.build().toUri(), HttpMethod.GET, entity, String.class);

            if (responseType == null) {
                response = (T) objectMapper.readValue(respEntityStr.getBody(), Map.class);
            } else {
                response = objectMapper.readValue(respEntityStr.getBody(), responseType);
            }

        } catch (Exception e) {
            throw new BizException(EnumException.CMM00.getMessage(), EnumException.CMM00.getCode());
        }

        return response;
    }
}

 

-- The End --