μλ° ν΄λμ€λ‘λ μ΄μ
μ€ν κ°λ₯ν JAR(Executable JAR) νμΌλ‘ μ€νλ μ€νλ§ μ ν리μΌμ΄μ μμ ν리λ§μ»€ ν νλ¦ΏμΌλ‘ μ μλ μ΄λ©μΌ ν νλ¦Ώμ 리μμ€λ‘ κ°μ Έμ€μ§ λͺ»νλ μ€λ₯κ° λ°μνλ€. μ²μμλ μλ‘κ² Amazon ECSμΌλ‘ ꡬμ±λ λ°°ν¬ νκ²½μμ μ¬μ©λ λΉλλ JAR νμΌμ ν νλ¦Ώ νμΌμ΄ ν¬ν¨λμ§ μμλ€κ³ μκ°νμ§λ§ μ ν¨μ€ λΉλ κ²°κ³Όλ₯Ό 보λ ν¨ν€μ§λ JAR νμΌμλ μ μμ μΌλ‘ 리μμ€ ν΄λμ νμΌλ€μ΄ ν¬ν¨λμ΄ μμμ νμΈν μ μμλ€. νκ°μ§ μ€μν λΆλΆμ λ¬Έμ κ° λ°μν μ½λλ€μ ParallelStream μΌλ‘ μΈν΄ ForkJoinPool.commonPool μ μ컀 μ€λ λλ‘ κΈ°λ‘λμ΄μλ€λ μ μ΄λ€. κ·Έλ¦¬κ³ λΉλ°λ²νΈ μ°ΎκΈ° μμ²μ μν μ΄λ©μΌ λ°μ‘μ λν ν νλ¦Ώμ μ μμ μΌλ‘ κ°μ Έμμ λ°μ‘λκ³ μμλ νμΈνμλ€. κ·Έλ λ€λ©΄, κ³Όμ° ForkJoinPool.commonPool μ€λ λ μμμλ 무μ¨μΌμ΄ λ°μνλ κ²μΌκΉ κΆκΈνλ€.
ForkJoinPool.commonPool
2025-06-27 04:31:00 [ForkJoinPool.commonPool-worker-5] ... class path resource [...] cannot be opened because it does not exist
μ€λ₯μ λν μμΈμ λν΄μ μ°Ύλ μ€ spring-boot#15737 μ΄μμμ ννΈλ₯Ό μ»μ μ μμλ€. JDK 9 μμλΆν° JDK-8172726 μ μν΄ ForkJoinPool.commonPool μμλ μμ μ€λ λκ° μλ μμ€ν
ν΄λμ€λ‘λκ° μ¬μ©λλ€λ κ²μ΄ μ€μν μ 보μ΄λ€. κ·Έλ¦¬κ³ ForkJoinPool μμ LaunchedClassLoader
λ₯Ό μ¬μ©ν μ μκ² μ€μ νμλ spring-boot#39843 ν°μΌλ μλ€.
ClassLoader in ClassPathResource
μ€νλ§ κΈ°λ° μ ν리μΌμ΄μ
μ λΉλ λ¨κ³μμ 리μμ€(resources) ν΄λλ₯Ό ν΄λμ€ν¨μ€μ ν¬ν¨
λ μ μλλ‘ WAR λλ JAR νμΌλ‘ ν¨ν€μ§λλ€. μ΄λ κ² ν¬ν¨λ 리μμ€λ μ μ 리μμ€λ‘ μ¬μ©μμκ² μ λ¬ν μλ μμ§λ§ μ ν리μΌμ΄μ
λ΄λΆμ μΌλ‘ λ‘λλμ΄ νμ©λ μ μλ€. ν΄λμ€ν¨μ€μ μ‘΄μ¬νλ 리μμ€λ₯Ό μ½κ² μ¬μ©ν μ μλλ‘ μ§μνλκ² μ€νλ§ νλ μμν¬μμ μ 곡νλ ClassPathResource ν΄λμ€λ€. ClassPathResourceμ μμ±μμμ ν΄λμ€λ‘λκ° μ§μ λμ§ μμΌλ©΄ ClassUtils.getDefaultClassLoader μ ν΄λμ€λ‘λλ₯Ό μ¬μ©νμ¬ λ¦¬μμ€λ₯Ό μ°Έμ‘°νκ² λλ€. μ½λ ꡬνμ μ΄ν΄λ³΄λ©΄ νμ¬ μ€λ μ€μ μ€μ λ 컨ν
μ€νΈ ν΄λμ€λ‘λλ₯Ό λ¨Όμ μ°Ύκ³ λ§μ§λ§μΌλ‘λ μμ€ν
ν΄λμ€λ‘λλ₯Ό ν΅ν΄ λΆνΈμ€νΈλ© ν΄λμ€λ‘λλ‘ μμνμ¬ λ¦¬μμ€λ₯Ό κ°μ Έμ¬ μ μμμ μ΄ν΄ν μ μλ€. μΌλ°μ μΈ ν΄λμ€λ‘λμ μ€λ λ 컨ν
μ€νΈ ν΄λμ€λ‘λμ μ°¨μ΄λ₯Ό 보면 ForkJoinPool.commonPool λ΄μ ContextClassLoaderκ° λ€λ₯Ό μ μμμ μ μ μλλ° μμ JDK-8172726 λ₯Ό ν΅ν΄ JDK 9 λΆν°λ ContextClassLoaderκ° μμ€ν
ν΄λμ€λ‘λλ‘ μ€μ λλ€
λ κ²μ νμΈνμλ€.
2025-06-29T04:03:25.603Z INFO 1 --- [springboot] [ scheduling-1] kr.kdev.demo.Application : jar:nested:/app.jar/!BOOT-INF/classes/!/test.txt, true, org.springframework.boot.loader.launch.LaunchedClassLoader@36baf30c, org.springframework.boot.loader.launch.LaunchedClassLoader@36baf30c
2025-06-29T04:03:25.602Z INFO 1 --- [springboot] [onPool-worker-2] kr.kdev.demo.Application : jar:nested:/app.jar/!BOOT-INF/classes/!/test.txt, true, org.springframework.boot.loader.launch.LaunchedClassLoader@36baf30c, jdk.internal.loader.ClassLoaders$AppClassLoader@502f3a78
2025-06-29T04:03:25.602Z INFO 1 --- [springboot] [onPool-worker-1] kr.kdev.demo.Application : jar:nested:/app.jar/!BOOT-INF/classes/!/test.txt, true, org.springframework.boot.loader.launch.LaunchedClassLoader@36baf30c, jdk.internal.loader.ClassLoaders$AppClassLoader@502f3a78
μμ κ°μ΄ ParellelStream λ΄μμλ ForkjoinPool.commonPool μΈ κ²½μ° LaunchedClassLoader
κ° μλ ClassLoaders$AppClassLoader
κ° μΆλ ₯λμμμ μ μ μμλ€. JDK λ²μ κ³Ό κ΄κ³μμ΄ ν΄λΉ λ¬Έμ κ° λ°μν μ μλ€λ μ΄μΌκΈ°λ‘ ForkJoinPool.commonPool μ μ€λ λ λ΄μμ ClassPathResourceλ₯Ό μ¬μ©ν λμλ μ¬λ°λ₯Έ ν΄λμ€λ‘λκ° μ¬μ©ν μ μλλ‘ μ λ¬ν΄μΌν¨
μ μ μ μλ€. κ·Έλ°λ°, μμ§ λ λ€λ₯Έ λ¬Έμ κ° λ¨μμλ€. ClasspathResourceλ₯Ό μ§μ μ¬μ©νλ μ½λλΌλ©΄ λΆλͺ¨ μ€λ λμ ν΄λμ€λ‘λλ₯Ό λͺ
μμ μΌλ‘ μ λ¬νλ©΄ ν΄κ²°μ΄ λλ€. κ·Έλ¬λ, μ΄λ©μΌ λ°μ‘μ μν΄ μ μλ μ΄λ©μΌ ν
νλ¦Ώμ κ°μ Έμ¬ λμλ ν리λ§μ»€ ν
νλ¦Ώ μμ§μ ν
νλ¦Ώ λ‘λλ‘ μμνκ² λλ€. λ λμκ°μλ Nested ννλ‘ κ³΅ν΅μ μΌλ‘ μ μλ λΆλΆμ΄ ν¬ν¨λ μ΄λ©μΌ ν
νλ¦ΏμΌλ‘ μ μλμ΄ λ―Έλ¦¬ ν
νλ¦Ώμ λΆλ¬μμ μΊμν μλ μλ μν©μΌλ‘ νμΈλλ€.
μΌλ¨, FreeMarkerConfigurationFactory.setResourceLoaderμ μ΄μ©ν΄λ³΄μμΌν κ² κ°λ€.