<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>donnert.net</title>
    <link>https://donnert.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 1 Jun 2026 00:30:25 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>donnert</managingEditor>
    <item>
      <title>스프링 부트에서 AWS Secrets manager 사용</title>
      <link>https://donnert.tistory.com/122</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;어플리케이션에서 설정 값을 쓸때 yml에 직접 넣거나,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이런 방식을 피하기 위해 AWS Parameter store를 사용하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Secrets manager가 Parameter store의 상위 호환처럼 보이기도 하는데 많지는 않지만 비용이 발생하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(자세한 설명은 &lt;a href=&quot;https://rainbound.tistory.com/entry/AWS-Parameter-Store-%EC%99%80-AWS-Secrets-Manager-%EA%B3%B5%ED%86%B5%EC%A0%90%EA%B3%BC-%EC%B0%A8%EC%9D%B4%EC%A0%90&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다른 블로그&lt;/a&gt;에서 참고)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;사전작업&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Secret 생성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;db_username, db_password 두개의 시크릿을 생성했다.&amp;nbsp; 별로 어려운건 없으니 이미지 보고 진행.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1630&quot; data-origin-height=&quot;1724&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baa8zv/btsf3ggEmgd/8yVDwyLOflTCJT6z7JAw3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baa8zv/btsf3ggEmgd/8yVDwyLOflTCJT6z7JAw3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baa8zv/btsf3ggEmgd/8yVDwyLOflTCJT6z7JAw3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbaa8zv%2Fbtsf3ggEmgd%2F8yVDwyLOflTCJT6z7JAw3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1630&quot; height=&quot;1724&quot; data-origin-width=&quot;1630&quot; data-origin-height=&quot;1724&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Secret name은 나중에 쓰이기 되니 기억!!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1628&quot; data-origin-height=&quot;844&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bU7eRT/btsf3qi7fKx/JgsWTsU5O6JC1Rp6sz8M1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bU7eRT/btsf3qi7fKx/JgsWTsU5O6JC1Rp6sz8M1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bU7eRT/btsf3qi7fKx/JgsWTsU5O6JC1Rp6sz8M1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbU7eRT%2Fbtsf3qi7fKx%2FJgsWTsU5O6JC1Rp6sz8M1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1628&quot; height=&quot;844&quot; data-origin-width=&quot;1628&quot; data-origin-height=&quot;844&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;자격증명 생성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IAM -&amp;gt; Users -&amp;gt; 사용자 선택 -&amp;gt; Security Credentials(탭)을 선택,&amp;nbsp;Access keys를 생성해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 나오는 Access Key ID와 Secret Access Key를 적어놓고 아래 자격증명에서 사용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(전 이미 생성되어 있음)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2860&quot; data-origin-height=&quot;786&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k4ELb/btsf4380ACD/Uke4bLKEohYpR2djiTLSJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k4ELb/btsf4380ACD/Uke4bLKEohYpR2djiTLSJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k4ELb/btsf4380ACD/Uke4bLKEohYpR2djiTLSJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk4ELb%2Fbtsf4380ACD%2FUke4bLKEohYpR2djiTLSJ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2860&quot; height=&quot;786&quot; data-origin-width=&quot;2860&quot; data-origin-height=&quot;786&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/cli/latest/userguide/getting-started-install.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AWS CLI&lt;/a&gt;가 없다면 설치를 해주고 아래처럼 자격증명 설정을 진행한다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1142&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kDkAp/btsf6EgEO2t/2mgoubWa0KzYlmGlqVS4kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kDkAp/btsf6EgEO2t/2mgoubWa0KzYlmGlqVS4kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kDkAp/btsf6EgEO2t/2mgoubWa0KzYlmGlqVS4kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkDkAp%2Fbtsf6EgEO2t%2F2mgoubWa0KzYlmGlqVS4kk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1142&quot; height=&quot;196&quot; data-origin-width=&quot;1142&quot; data-origin-height=&quot;196&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사전 작업이 완료되면 드디어 개발을 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;스프링 부트 어플리케이션 개발&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;라이브러리 종속성 추가(build.gradle.kts)&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1684214677524&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;implementation(&quot;io.awspring.cloud:spring-cloud-starter-aws-secrets-manager-config:2.4.4&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;설정파일 추가(application.yml)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시크릿 생성 시에 사용했던 Secret name을 잘 기억해뒀다가 아래 입력한다(sample/secretsManager/dev)&lt;/p&gt;
&lt;pre id=&quot;code_1684214656019&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  config:
    import: 'aws-secretsmanager:sample/secretsManager/dev'&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;테스트 코드 작성&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1684215341570&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.test.context.SpringBootTest

@SpringBootTest
class SecretsManagerTest {

    @Value(&quot;\${db_username}&quot;)
    lateinit var dbUsername : String

    @Value(&quot;\${db_password}&quot;)
    lateinit var dbPassword : String

    @Test
    fun test() {
        assertThat(dbUsername).isEqualTo(&quot;username&quot;)
        assertThat(dbPassword).isEqualTo(&quot;password&quot;)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;DB 설정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(변수명을 username(기본)으로 할 경우 환경변수와 충돌이 일어나는 경우가 있어서 키 값을 변경해주었다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;aws 설정&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3110&quot; data-origin-height=&quot;1456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKdLos/btshjdJGJ46/FhIJ2SCDbmjfskTKs5a2L1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKdLos/btshjdJGJ46/FhIJ2SCDbmjfskTKs5a2L1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKdLos/btshjdJGJ46/FhIJ2SCDbmjfskTKs5a2L1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKdLos%2FbtshjdJGJ46%2FFhIJ2SCDbmjfskTKs5a2L1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3110&quot; height=&quot;1456&quot; data-origin-width=&quot;3110&quot; data-origin-height=&quot;1456&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;application.yml&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1684990120254&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  config:
    import: 'aws-secretsmanager:sample/secretsManager/dev'
  datasource:
    url: jdbc:oracle:thin:@${dbHost}:${dbPort}:${dbName}
    username: ${dbUsername}
    password: ${dbPassword}
    driver-class-name: oracle.jdbc.OracleDriver&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발/Java, Kotlin</category>
      <category>AWS</category>
      <category>cloud</category>
      <category>Kotlin</category>
      <category>Secrets Manager</category>
      <category>serets</category>
      <category>Spring</category>
      <category>spring boot</category>
      <author>donnert</author>
      <guid isPermaLink="true">https://donnert.tistory.com/122</guid>
      <comments>https://donnert.tistory.com/122#entry122comment</comments>
      <pubDate>Tue, 16 May 2023 14:38:10 +0900</pubDate>
    </item>
    <item>
      <title>Spring Database Naming(prefix)</title>
      <link>https://donnert.tistory.com/121</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;그닥 좋은 방법은 아니지만 알아두면 요긴하게 쓰일떄가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 경우 스키마를 분리하기가 곤란한 환경일때 아래와 같이 사용한 적이 있으니 내용 참고.&lt;/p&gt;
&lt;pre id=&quot;code_1679968172517&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class CustomTableStrategy: PhysicalNamingStrategy {
    private val prefix = &quot;dev_&quot;
    override fun toPhysicalCatalogName(logicalName: Identifier?, jdbcEnvironment: JdbcEnvironment?): Identifier? {
        return logicalName
    }

    override fun toPhysicalSchemaName(logicalName: Identifier?, jdbcEnvironment: JdbcEnvironment?): Identifier? {
        return logicalName
    }

    override fun toPhysicalTableName(logicalName: Identifier?, jdbcEnvironment: JdbcEnvironment?): Identifier? {
        return if(logicalName == null ) null else Identifier.toIdentifier(prefix + logicalName.text)
    }

    override fun toPhysicalSequenceName(logicalName: Identifier?, jdbcEnvironment: JdbcEnvironment?): Identifier? {
        return logicalName
    }

    override fun toPhysicalColumnName(logicalName: Identifier?, jdbcEnvironment: JdbcEnvironment?): Identifier? {
        return logicalName
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;application.yml&lt;/h4&gt;
&lt;pre id=&quot;code_1679985065191&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  jpa:
    properties:
      hibernate:
        physical_naming_strategy: net.donnert.sample.common.CustomTableStrategy&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Java, Kotlin</category>
      <category>Database</category>
      <category>DB</category>
      <category>JDBC</category>
      <category>prefix</category>
      <category>Spring</category>
      <author>donnert</author>
      <guid isPermaLink="true">https://donnert.tistory.com/121</guid>
      <comments>https://donnert.tistory.com/121#entry121comment</comments>
      <pubDate>Tue, 28 Mar 2023 10:52:51 +0900</pubDate>
    </item>
    <item>
      <title>Pair, Triple</title>
      <link>https://donnert.tistory.com/120</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;함수에서 응답을 받을떄 애매하게 값을 여러개 리턴해야 하는 경우가 있는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴떄 귀찮아서 Pair, Triple을 종종 사용하는 편입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 1번 사용 예제처럼 Pair.first를 사용하는 경우가 많은데 2번처럼 바로 변수에 바인딩 해서 사용할 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드도 간단해지고 아래쪽에서 first가 뭐였더라 같은 삽질을 할 필요가 없습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1678342659875&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun main() {
    // 1
    val widthHeight = getWidthHeight()
    println(&quot;Width: ${widthHeight.first}, Height: ${widthHeight.second}&quot;)
    
    // 2
    // val xyz = getXYZ()
    // val x = xyz.first
    // val y = xyz.second
    // val z = xyz.third
    val (x, y, z) = getXYZ()
    println(&quot;X: $x, Y: $y, Z: $z&quot;)
}

fun getWidthHeight(): Pair&amp;lt;*, *&amp;gt; {
    return Pair(100,200)
}

fun getXYZ(): Triple&amp;lt;*, *, *&amp;gt; {
    return Triple(10, 20, 30)
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발/Java, Kotlin</category>
      <category>Kotlin</category>
      <category>pair</category>
      <category>Triple</category>
      <author>donnert</author>
      <guid isPermaLink="true">https://donnert.tistory.com/120</guid>
      <comments>https://donnert.tistory.com/120#entry120comment</comments>
      <pubDate>Thu, 9 Mar 2023 15:24:23 +0900</pubDate>
    </item>
    <item>
      <title>RestTemplate 사용 중 Connection refused: connect 오류 발생</title>
      <link>https://donnert.tistory.com/119</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;평소처럼 restTemplate를 사용하다가 이상하게 연동이 안되는 상황 발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(서버는 npm의 json-server 사용)&lt;/p&gt;
&lt;pre id=&quot;code_1676944597441&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    fun getTest() {
        val body = restTemplate.getForEntity(&quot;$host/test&quot;, String::class.java).body
        logger.info {&quot;body : $body&quot;}
    }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1676944504172&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;o.s.web.client.RestTemplate              : HTTP GET http://localhost:3020/test
o.s.web.client.RestTemplate              : Accept=[text/plain, application/json, application/*+json, */*]
o.s.s.s.TaskUtils$LoggingErrorHandler    : Unexpected error occurred in scheduled task

org.springframework.web.client.ResourceAccessException: I/O error on GET request for &quot;http://localhost:3020/test&quot;: Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:791) ~[spring-web-5.3.25.jar:5.3.25]
	at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:717) ~[spring-web-5.3.25.jar:5.3.25]
	at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:367) ~[spring-web-5.3.25.jar:5.3.25]
	at com.redmine.redminehelper.TestService.getTest(TestService.kt:28) ~[main/:na]
	at com.redmine.redminehelper.TestWatcher.watch(TestWatcher.kt:21) ~[main/:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_342]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_342]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_342]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_342]
	at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) ~[spring-context-5.3.25.jar:5.3.25]
	at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-5.3.25.jar:5.3.25]
	...
Caused by: java.net.ConnectException: Connection refused: connect
	at java.net.DualStackPlainSocketImpl.connect0(Native Method) ~[na:1.8.0_342]
	at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79) ~[na:1.8.0_342]
	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_342]
	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[na:1.8.0_342]
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[na:1.8.0_342]
	at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) ~[na:1.8.0_342]
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[na:1.8.0_342]
	at java.net.Socket.connect(Socket.java:613) ~[na:1.8.0_342]
	at java.net.Socket.connect(Socket.java:561) ~[na:1.8.0_342]
	at sun.net.NetworkClient.doConnect(NetworkClient.java:180) ~[na:1.8.0_342]
	at sun.net.www.http.HttpClient.openServer(HttpClient.java:463) ~[na:1.8.0_342]
	at sun.net.www.http.HttpClient.openServer(HttpClient.java:558) ~[na:1.8.0_342]
	at sun.net.www.http.HttpClient.&amp;lt;init&amp;gt;(HttpClient.java:242) ~[na:1.8.0_342]
	at sun.net.www.http.HttpClient.New(HttpClient.java:339) ~[na:1.8.0_342]
	at sun.net.www.http.HttpClient.New(HttpClient.java:357) ~[na:1.8.0_342]
	at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1233) ~[na:1.8.0_342]
	...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상한건 curl이나 브라우저로는 연동이 잘 되는데 스프링을 통해서만 안되는 기현상&lt;/p&gt;
&lt;pre id=&quot;code_1676944799924&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; curl http://localhost:3020/test
StatusCode        : 200
StatusDescription : OK
Content           : {
                      &quot;result&quot;: &quot;true&quot;
                    }
RawContent        : HTTP/1.1 200 OK
                    Vary: Origin, Accept-Encoding
                    Access-Control-Allow-Credentials: true
                    Pragma: no-cache
                    X-Content-Type-Options: nosniff
                    Connection: keep-alive
                    Keep-Alive: timeout=5
                    Content-Length...
Headers           : {[Vary, Origin, Accept-Encoding], [Access-Control-Allow-Credentials, true], [Pragma, no-cache], [X-
                    Content-Type-Options, nosniff]...}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 22&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;해결&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;restTemplate에서 &lt;span style=&quot;background-color: #ffffff; color: #232629;&quot;&gt;SimpleClientHttpRequestFactory라는 &lt;/span&gt;내부 http 클라이언트를 사용하는데 이놈이 문제인듯,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아파치에서 제공하는 httpClient로 교체해주면 해결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디펜던시만 추가해주면 내부에서 알아서 우선순위를 올리는 듯 하니 소스 수정 없이 build파일만 수정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1676945021784&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// build.gradle.kts
implementation(&quot;org.apache.httpcomponents:httpclient:4.5.14&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성공&lt;/p&gt;
&lt;pre id=&quot;code_1676956605273&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;o.s.web.client.RestTemplate              : HTTP GET http://localhost:3020/test
o.s.web.client.RestTemplate              : Accept=[text/plain, application/json, application/*+json, */*]
o.a.h.client.protocol.RequestAddCookies  : CookieSpec selected: default
o.a.h.client.protocol.RequestAuthCache   : Auth cache not set in the context
h.i.c.PoolingHttpClientConnectionManager : Connection request: [route: {}-&amp;gt;http://localhost:3020][total available: 1; route allocated: 1 of 5; total allocated: 1 of 10]
org.apache.http.impl.conn.CPool          : Connection [id:2][route:{}-&amp;gt;http://localhost:3020][state:null] expired @ Tue Feb 21 14:15:24 KST 2023
h.i.c.DefaultManagedHttpClientConnection : http-outgoing-2: Close connection
h.i.c.PoolingHttpClientConnectionManager : Connection leased: [id: 3][route: {}-&amp;gt;http://localhost:3020][total available: 0; route allocated: 1 of 5; total allocated: 1 of 10]
o.a.http.impl.execchain.MainClientExec   : Opening connection {}-&amp;gt;http://localhost:3020
.i.c.DefaultHttpClientConnectionOperator : Connecting to localhost/127.0.0.1:3020
.i.c.DefaultHttpClientConnectionOperator : Connect to localhost/127.0.0.1:3020 timed out. Connection will be retried using another IP address
.i.c.DefaultHttpClientConnectionOperator : Connecting to localhost/0:0:0:0:0:0:0:1:3020
.i.c.DefaultHttpClientConnectionOperator : Connection established 0:0:0:0:0:0:0:1:3146&amp;lt;-&amp;gt;0:0:0:0:0:0:0:1:3020
o.a.http.impl.execchain.MainClientExec   : Executing request GET /test HTTP/1.1
o.a.http.impl.execchain.MainClientExec   : Target auth state: UNCHALLENGED
o.a.http.impl.execchain.MainClientExec   : Proxy auth state: UNCHALLENGED
org.apache.http.headers                  : http-outgoing-3 &amp;gt;&amp;gt; GET /test HTTP/1.1
org.apache.http.headers                  : http-outgoing-3 &amp;gt;&amp;gt; Accept: text/plain, application/json, application/*+json, */*
org.apache.http.headers                  : http-outgoing-3 &amp;gt;&amp;gt; Host: localhost:3020
org.apache.http.headers                  : http-outgoing-3 &amp;gt;&amp;gt; Connection: Keep-Alive
org.apache.http.headers                  : http-outgoing-3 &amp;gt;&amp;gt; User-Agent: Apache-HttpClient/4.5.14 (Java/1.8.0_342)
org.apache.http.headers                  : http-outgoing-3 &amp;gt;&amp;gt; Accept-Encoding: gzip,deflate
org.apache.http.wire                     : http-outgoing-3 &amp;gt;&amp;gt; &quot;GET /test HTTP/1.1[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;gt;&amp;gt; &quot;Accept: text/plain, application/json, application/*+json, */*[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;gt;&amp;gt; &quot;Host: localhost:3020[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;gt;&amp;gt; &quot;Connection: Keep-Alive[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;gt;&amp;gt; &quot;User-Agent: Apache-HttpClient/4.5.14 (Java/1.8.0_342)[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;gt;&amp;gt; &quot;Accept-Encoding: gzip,deflate[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;gt;&amp;gt; &quot;[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;HTTP/1.1 200 OK[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;X-Powered-By: Express[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;Vary: Origin, Accept-Encoding[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;Access-Control-Allow-Credentials: true[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;Cache-Control: no-cache[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;Pragma: no-cache[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;Expires: -1[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;X-Content-Type-Options: nosniff[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;Content-Type: application/json; charset=utf-8[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;Content-Length: 22[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;ETag: W/&quot;16-yzVxm7zLek+JyDn3hOpcSoZ9L4A&quot;[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;Date: Tue, 21 Feb 2023 05:15:31 GMT[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;Connection: keep-alive[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;Keep-Alive: timeout=5[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;[\r][\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;{[\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;  &quot;result&quot;: &quot;true&quot;[\n]&quot;
org.apache.http.wire                     : http-outgoing-3 &amp;lt;&amp;lt; &quot;}&quot;
org.apache.http.headers                  : http-outgoing-3 &amp;lt;&amp;lt; HTTP/1.1 200 OK
org.apache.http.headers                  : http-outgoing-3 &amp;lt;&amp;lt; X-Powered-By: Express
org.apache.http.headers                  : http-outgoing-3 &amp;lt;&amp;lt; Vary: Origin, Accept-Encoding
org.apache.http.headers                  : http-outgoing-3 &amp;lt;&amp;lt; Access-Control-Allow-Credentials: true
org.apache.http.headers                  : http-outgoing-3 &amp;lt;&amp;lt; Cache-Control: no-cache
org.apache.http.headers                  : http-outgoing-3 &amp;lt;&amp;lt; Pragma: no-cache
org.apache.http.headers                  : http-outgoing-3 &amp;lt;&amp;lt; Expires: -1
org.apache.http.headers                  : http-outgoing-3 &amp;lt;&amp;lt; X-Content-Type-Options: nosniff
org.apache.http.headers                  : http-outgoing-3 &amp;lt;&amp;lt; Content-Type: application/json; charset=utf-8
org.apache.http.headers                  : http-outgoing-3 &amp;lt;&amp;lt; Content-Length: 22
org.apache.http.headers                  : http-outgoing-3 &amp;lt;&amp;lt; ETag: W/&quot;16-yzVxm7zLek+JyDn3hOpcSoZ9L4A&quot;
org.apache.http.headers                  : http-outgoing-3 &amp;lt;&amp;lt; Date: Tue, 21 Feb 2023 05:15:31 GMT
org.apache.http.headers                  : http-outgoing-3 &amp;lt;&amp;lt; Connection: keep-alive
org.apache.http.headers                  : http-outgoing-3 &amp;lt;&amp;lt; Keep-Alive: timeout=5
o.a.http.impl.execchain.MainClientExec   : Connection can be kept alive for 5000 MILLISECONDS
o.s.web.client.RestTemplate              : Response 200 OK
o.s.web.client.RestTemplate              : Reading to [java.lang.String] as &quot;application/json;charset=utf-8&quot;
h.i.c.PoolingHttpClientConnectionManager : Connection [id: 3][route: {}-&amp;gt;http://localhost:3020] can be kept alive for 5.0 seconds
h.i.c.DefaultManagedHttpClientConnection : http-outgoing-3: set socket timeout to 0
h.i.c.PoolingHttpClientConnectionManager : Connection released: [id: 3][route: {}-&amp;gt;http://localhost:3020][total available: 1; route allocated: 1 of 5; total allocated: 1 of 10]
c.s.r.r.codemind.CodeMindService         : result : true
c.s.r.r.codemind.CodeMindService         : body : {
  &quot;result&quot;: &quot;true&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Java, Kotlin</category>
      <category>apache</category>
      <category>HttpClient</category>
      <category>java</category>
      <category>Kotlin</category>
      <category>resttemplate</category>
      <category>WebClient</category>
      <author>donnert</author>
      <guid isPermaLink="true">https://donnert.tistory.com/119</guid>
      <comments>https://donnert.tistory.com/119#entry119comment</comments>
      <pubDate>Tue, 21 Feb 2023 11:06:28 +0900</pubDate>
    </item>
    <item>
      <title>Spread operator(전개구문) in kotlin</title>
      <link>https://donnert.tistory.com/118</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;전개구문은 배열처럼 여러 요소가 하나로 관리될때 이를 풀어서 요소들로 나열할떄 사용됩니다.&lt;b&gt;&lt;span style=&quot;font-size: 1.5rem;&quot;&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 1.5rem;&quot;&gt;Javascript(Typescript)&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1670304576662&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    const arr1 = [0,1,2]
    const arr2 = [...arr1, 3]
    const arr3 = [...arr2, 1]
    
    console.log(arr3)
    
    // 결과
    // (5) [0, 1, 2, 3, 1]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 1.5rem;&quot;&gt;Kotlin&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;    val arr1 = arrayOf(0,1,2)
    val arr2 = arrayOf(*arr1, 3)
    val arr3 = arrayOf(*arr2, 1)
    
    println(arr3.joinToString())
    
    // 결과
    // 0, 1, 2, 3, 1&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 1.5rem;&quot;&gt;결론&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트에 비하면 배열 타입만 사용 가능하기 때문에&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot; data-ke-size=&quot;size16&quot;&gt;리스트 같은 경우 TypedArray로 변환해서 사용해야 하는등.. 제약이 많습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot; data-ke-size=&quot;size16&quot;&gt;다음 예제를 보면 자바스크립트에서 전개구문이 얼마나 유용한지 볼 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 1.5rem;&quot;&gt;번외&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1670306923412&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    const json1 = { name: &quot;Joe&quot;, location: &quot;Seoul&quot; }
    const json2 = { language: &quot;Kotlin&quot; }
    const json3 = {
      no : 1,
      ...json1,
      ...json2,
      location: &quot;Busan&quot;,
    }
    
    console.log(JSON.stringify(json3))     
    
    // 결과
    // {&quot;no&quot;:1,&quot;name&quot;:&quot;Joe&quot;,&quot;location&quot;:&quot;Busan&quot;,&quot;language&quot;:&quot;Kotlin&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Java, Kotlin</category>
      <category>Kotlin</category>
      <category>spread operator</category>
      <category>TypeScript</category>
      <category>전개구문</category>
      <author>donnert</author>
      <guid isPermaLink="true">https://donnert.tistory.com/118</guid>
      <comments>https://donnert.tistory.com/118#entry118comment</comments>
      <pubDate>Tue, 6 Dec 2022 22:51:14 +0900</pubDate>
    </item>
    <item>
      <title>리눅스 콘솔 파일로 출력</title>
      <link>https://donnert.tistory.com/117</link>
      <description>&lt;p style=&quot;text-align: left; clear: none; float: none;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# 파일에 기록
./test.sh &amp;gt; log.txt

# 파일에 기록(Append)
./test.sh &amp;gt;&amp;gt; log.txt

# 파일에 기록(stderr 포함)
./test.sh &amp;gt;&amp;amp;1 | tee log.txt

# 파일에 기록(stderr 포함+콘솔 출력)
./test.sh 2&amp;gt;&amp;amp;1 | tee log.txt

# 응용(시간 추가)
DATE=$(date '+%Y%m%d%H%M%S')
./test.sh 2&amp;gt;&amp;amp;1 | tee log_$DATE.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Linux, Server</category>
      <category>date</category>
      <category>Linux</category>
      <category>Shell</category>
      <author>donnert</author>
      <guid isPermaLink="true">https://donnert.tistory.com/117</guid>
      <comments>https://donnert.tistory.com/117#entry117comment</comments>
      <pubDate>Tue, 4 Oct 2022 13:29:58 +0900</pubDate>
    </item>
    <item>
      <title>ideavimrc</title>
      <link>https://donnert.tistory.com/116</link>
      <description>&lt;p&gt;Intellij ideavim 플러그인 사용 시 다음의 파일을 홈 경로에 넣어준다.&lt;/p&gt;
&lt;p&gt;(윈도우의 경우 C:\Users\donnert\.ideavimrc)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;인텔리제이의 경우 액션(:action)을 지원해서 그냥 가져다가 키랑 매핑해서 쓰기만 하면 된다&lt;/p&gt;
&lt;p&gt;(&lt;a href=&quot;https://gist.github.com/zchee/9c78f91cc5ad771c1f5d&quot;&gt;https://gist.github.com/zchee/9c78f91cc5ad771c1f5d&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;주요기능&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;세미콜론도 콜론으로&lt;/p&gt;
&lt;p&gt;jj : 입력모드 탈출&lt;/p&gt;
&lt;p&gt;H : 줄 제일 앞&lt;/p&gt;
&lt;p&gt;L : 줄 제일 뒤&lt;/p&gt;
&lt;p&gt;컨트롤+H : 뒤로가기&lt;/p&gt;
&lt;p&gt;컨트롤+L : 앞으로 가기&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;gfu : 클래스/메소드 사용하는부분 찾기&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;gd: 변수 선언으로 이동&lt;/p&gt;
&lt;p&gt;gb: 변수 타입 선언으로 이용&lt;/p&gt;
&lt;p&gt;grn : 이름 변경(변수 클래스 등)&lt;/p&gt;
&lt;p&gt;gw : 단어 선택&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;i&gt;&lt;b&gt;.ideavimrc&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1588121739018&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot; 기본설정

set ignorecase
set smartcase
set expandtab
set hlsearch
set incsearch

imap jj &amp;lt;ESC&amp;gt;

let mapleader=&quot;g&quot;

nnoremap ; :

vnoremap ; :


noremap H ^
noremap L $

nnoremap &amp;lt;leader&amp;gt;fu :action FindUsages&amp;lt;cr&amp;gt;
nnoremap &amp;lt;leader&amp;gt;rn :action RenameElement&amp;lt;cr&amp;gt;
nnoremap &amp;lt;leader&amp;gt;aw :action ActivateServicesToolWindow&amp;lt;cr&amp;gt;
nnoremap &amp;lt;leader&amp;gt;i :action GotoImplementation&amp;lt;cr&amp;gt;
nnoremap &amp;lt;leader&amp;gt;cc :action CloseContent&amp;lt;cr&amp;gt;
nnoremap &amp;lt;leader&amp;gt;b :action GotoTypeDeclaration&amp;lt;cr&amp;gt;
nnoremap &amp;lt;C-H&amp;gt; :action Back&amp;lt;CR&amp;gt;
nnoremap &amp;lt;C-L&amp;gt; :action Forward&amp;lt;CR&amp;gt;
nnoremap &amp;lt;leader&amp;gt;w :action EditorSelectWord&amp;lt;CR&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>ideavim</category>
      <category>ideavimrc</category>
      <category>IntelliJ</category>
      <category>jetBrains</category>
      <category>vim</category>
      <category>인텔리제이</category>
      <author>donnert</author>
      <guid isPermaLink="true">https://donnert.tistory.com/116</guid>
      <comments>https://donnert.tistory.com/116#entry116comment</comments>
      <pubDate>Wed, 29 Apr 2020 10:01:56 +0900</pubDate>
    </item>
    <item>
      <title>히카리 풀 모니터링</title>
      <link>https://donnert.tistory.com/115</link>
      <description>&lt;p&gt;히카리 풀을 사용하게 되면 housekeeper란 놈이 기본으로 30초마다 풀 상태를 debug모드로 찍고있는데&lt;/p&gt;
&lt;p&gt;커스터마이징이 잘 안되서 별도로 찍기로 함&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1588040468241&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@SpringBootApplication
@EnableScheduling
class ApiApplication(
        val dataSource: DataSource) {

    @Scheduled(fixedDelay = 10000)
    fun hikariPoolMonitor() {
        (DirectFieldAccessor(dataSource).getPropertyValue(&quot;pool&quot;) as HikariPool?)?.let { hikariPool -&amp;gt;
            logger().info(&quot;Pool stats (total=${hikariPool.totalConnections}, active=${hikariPool.activeConnections}, idle=${hikariPool.idleConnections}, waiting=${hikariPool.threadsAwaitingConnection})&quot;)
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1588040779979&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;2020-04-28 11:22:58,868 INFO  [scheduling-1] [||] [n.d.api.ApiApplication:23] : Pool stats (total=50, active=0, idle=50, waiting=0)
2020-04-28 11:23:08,868 INFO  [scheduling-1] [||] [n.d.api.ApiApplication:23] : Pool stats (total=50, active=0, idle=50, waiting=0)
2020-04-28 11:23:18,869 INFO  [scheduling-1] [||] [n.d.api.ApiApplication:23] : Pool stats (total=50, active=0, idle=50, waiting=0)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발/Java, Kotlin</category>
      <category>Connection Pool</category>
      <category>Hikari</category>
      <category>housekeeper</category>
      <category>Kotlin</category>
      <category>monitoring</category>
      <category>Pool</category>
      <category>부트</category>
      <category>스프링</category>
      <category>코틀린</category>
      <category>히카리</category>
      <author>donnert</author>
      <guid isPermaLink="true">https://donnert.tistory.com/115</guid>
      <comments>https://donnert.tistory.com/115#entry115comment</comments>
      <pubDate>Tue, 28 Apr 2020 11:22:09 +0900</pubDate>
    </item>
    <item>
      <title>도커 빌드 속도가 느릴 경우</title>
      <link>https://donnert.tistory.com/114</link>
      <description>&lt;p&gt;Dockerfile을 소스와 같이 관리하기 위해 프로젝트 최상단에 위치 시킴&lt;/p&gt;
&lt;p&gt;gradle build 후 docker build 수행하니 시간이 엄청 길어지면서 용량도 커지는 현상 발생&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;원인은 도커 빌드시 Dockerfile 하위 파일을 다 이미지에 넣어버리는 것으로 확인&lt;/p&gt;
&lt;p&gt;.dockerignore파일을 프로젝트 최상단에 위치시켜서 예외 항목 등록 후 정상 동작 확인&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000; font-size: 1.62em; letter-spacing: -1px;&quot;&gt;.dockerignore&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1581920810950&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;**
!/target/*.jar&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Linux, Server</category>
      <category>docker</category>
      <category>dockerignore</category>
      <category>도커</category>
      <author>donnert</author>
      <guid isPermaLink="true">https://donnert.tistory.com/114</guid>
      <comments>https://donnert.tistory.com/114#entry114comment</comments>
      <pubDate>Mon, 17 Feb 2020 15:30:34 +0900</pubDate>
    </item>
    <item>
      <title>동기(Synchronous)/비동기(Asynchronous) 처리</title>
      <link>https://donnert.tistory.com/112</link>
      <description>&lt;p&gt;다음과 같이 여러개의 작업을 동시에 처리할때 작업1,2가 메인작업과 별개의 작업일때&lt;/p&gt;
&lt;p&gt;비동기(@Async)로 던져놓고 메인 작업만 완료 후 응답을 주기도 합니다.&lt;/p&gt;
&lt;p&gt;(응답시간 0.5초, 작업1,2의 결과 받을 수 없음)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;메인작업 : 0.5초&lt;/p&gt;
&lt;p&gt;작업1 : 1초&lt;/p&gt;
&lt;p&gt;작업2 : 2초&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;하지만 3가지 작업의 결과가 모두 필요할 경우 동기 처리를 하면 3.5초가 걸리지만&lt;/p&gt;
&lt;p&gt;작업1, 2를 비동기로 처리하면 일찍 처리가 끝난 작업은 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;모든 작업이 완료될때까지 대기 후 응답을 줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;(응답시간 2초, 3개의 작업 결과 확인 가능)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 1.5rem;&quot;&gt;Kotlin&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;@RestController
@EnableAsync
class ThreadTest(
        val taskService: TaskService,
        val mainService: MainService
) {
    @GetMapping(&quot;task&quot;)
    fun testMapping(): String {
        val start = System.currentTimeMillis()

        val task1 = taskService.task1()
        val task2 = taskService.task2()
        val main = mainService.task()

        return &quot;main[$main], task1[${task1.get()}], task2[${task2.get()}], total[${System.currentTimeMillis()-start}]&quot;
    }
}

@Service
class MainService {
    fun task(): Long {
        val start = System.currentTimeMillis()
        Thread.sleep(500)
        return (System.currentTimeMillis()-start)
    }
}

@Service
class TaskService {
    @Async
    fun task1(): CompletableFuture&amp;lt;Long&amp;gt; {
        val start = System.currentTimeMillis()
        Thread.sleep(1000)
        return CompletableFuture.completedFuture(System.currentTimeMillis()-start)
    }

    @Async
    fun task2(): CompletableFuture&amp;lt;Long&amp;gt; {
        val start = System.currentTimeMillis()
        Thread.sleep(2000)
        return CompletableFuture.completedFuture(System.currentTimeMillis()-start)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 1.5rem;&quot;&gt;테스트1&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;http://localhost:8080/task&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px; background-color: #f6e199;&quot;&gt;main[502],&amp;nbsp;task1[1001],&amp;nbsp;task2[2001],&amp;nbsp;total[2007]&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;br /&gt;메인 작업은 처리 완료 후 비동기 작업들이 완료될때까지 대기 후 응답을 주고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 1.5rem;&quot;&gt;테스트2&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;반대로 동기로 처리하는 메인작업이 오래걸릴 경우도 테스트 해보겠습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;(MainService의 작업시간을 3초로 늘려주세요)&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;메인작업 : 3초&lt;/p&gt;
&lt;p&gt;작업1 : 1초&lt;/p&gt;
&lt;p&gt;작업2 : 2초&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;http://localhost:8080/task&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;letter-spacing: 0px; background-color: #f6e199;&quot;&gt;main[3001],&amp;nbsp;task1[1001],&amp;nbsp;task2[2001],&amp;nbsp;total[3004]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;br /&gt;당연히 메인작업이 처리되는동안 1,2번 작업은 비동기로 작업을 완료하고 응답을 같이 주고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;* 동시에 여러 곳을 연동해서 결과를 취합한다거나&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp; 자원이 남아 별도의 스레드에서 처리하고자 할 때 사용하시면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Java, Kotlin</category>
      <category>async</category>
      <category>Asynchronous</category>
      <category>java</category>
      <category>Kotlin</category>
      <category>Sync</category>
      <category>Synchronous</category>
      <category>동기</category>
      <category>비동기</category>
      <category>자바</category>
      <category>코틀린</category>
      <author>donnert</author>
      <guid isPermaLink="true">https://donnert.tistory.com/112</guid>
      <comments>https://donnert.tistory.com/112#entry112comment</comments>
      <pubDate>Wed, 27 Nov 2019 14:48:01 +0900</pubDate>
    </item>
  </channel>
</rss>