λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
πŸ’Š Java & Kotlin & Spring/- Java & kotlin

[쑰금 더 κΉŠμ€ Java] JRE의 Classloader 에 λŒ€ν•΄ μ•Œμ•„λ³΄μž

by Wonit 2021. 12. 2.

 

μ˜€λŠ˜μ€ JRE의 핡심 κ΅¬μ„±μš”μ†ŒμΈ Classloader에 λŒ€ν•΄μ„œ μ•Œμ•„λ³΄λ € ν•œλ‹€.

 

μ§€λ‚œ μ‹œκ°„ μš°λ¦¬λŠ” Java Bytecode 에 λŒ€ν•΄μ„œ μ•Œμ•„λ³΄μ•˜λ‹€.

 

[쑰금 더 κΉŠμ€ Java] Java Bytecode λ₯Ό μ•Œμ•„λ³΄μž (μžλ°”λ₯Ό μ»΄νŒŒμΌν•˜λ©΄ μ–΄λ–€ 일이 μΌμ–΄λ‚ κΉŒ?)

μš°λ¦¬λŠ” λ§Žμ€ μ‹œκ°„ Javaλ₯Ό μ΄μš©ν•΄μ„œ λ‹€μ–‘ν•œ μ†Œν”„νŠΈμ›¨μ–΄λ₯Ό κ°œλ°œν•˜λ©΄μ„œ λ“€μ—ˆλ˜ μ†Œλ¦¬κ°€ μžˆλ‹€. JavaλŠ” JVM 이 있기 λ•Œλ¬Έμ— ν”Œλž«νΌμ— 쒅속적이지 μ•Šκ³  이식성이 λ›°μ–΄λ‚˜λ‹€. κ·Έ μ΄μœ μ— λŒ€ν•΄μ„œ 생각해본 κ²½

wonit.tistory.com

 

μš°λ¦¬κ°€ .java νŒŒμΌμ„ μ»΄νŒŒμΌν•œλ‹€λ©΄ .class λΌλŠ” λ°”μ΄νŠΈ μ½”λ“œλ‘œ λ³€ν™˜μ΄λ˜κ³  JVM이 ν•΄λ‹Ή class νŒŒμΌμ„ λ™μ μœΌλ‘œ μ‹€ν–‰ν•˜λŠ” κ³Όμ •μ—μ„œ κ°€μž₯ μ€‘μš”ν•œ 것이 λ°”λ‘œ ClassLoader 이닀.

 

Java ClassLoader

 

Java의 ClassLoader λŠ” JRE의 κ΅¬μ„±μš”μ†Œ 쀑 ν•˜λ‚˜μ΄λ‹€.

 

JREλŠ” JVMκ³Ό Core Java Library λ₯Ό ν¬ν•¨ν•˜λ©° ClassLoader 도 ν•¨κ»˜ ν¬ν•¨ν•œλ‹€.

 

javac μ»΄νŒŒμΌλŸ¬μ— μ˜ν•΄ μ‚¬μš©μžκ°€ μž‘μ„±ν•œ .java μ†ŒμŠ€μ½”λ“œλ₯Ό μ»΄νŒŒμΌν•˜μ—¬ Bytecode λ₯Ό μƒμ„±ν•˜κ³  ν•΄λ‹Ή .class νŒŒμΌμ„ Runtime 으둜 κ°€μ Έκ°€λŠ” 이 μ‹œμ μ— Java ClassLoader κ°€ λ™μž‘ν•œλ‹€.

 

이 μ‹œμ μ—μ„œ λ‹€μ‹œ ν•œ 번 μžλ°” ν΄λž˜μŠ€λ‘œλ”μ˜ μ •μ˜λ₯Ό λ‚΄λ €λ³΄μžλ©΄

 

μžλ°” λ°”μ΄νŠΈμ½”λ“œλ₯Ό JVM 으둜 동적 λ‘œλ“œν•˜λŠ” Java Runtime Environment (JRE)의 일뢀이닀.

 

μ΄λŸ¬ν•œ Java ClassLoader κ°€ 있기 λ•Œλ¬Έμ— Host PC의 파일과 파일 μ‹œμŠ€ν…œμ— λŒ€ν•΄μ„œ μ•Œ ν•„μš”κ°€ μ—†κ³  ν”Œλž«νΌμ— λ…λ¦½μ μ΄κ²Œ λ˜λŠ” 것이닀.

μœ„μ—μ„œ 동적 λ‘œλ“œν•˜λŠ” λΌλŠ” 말을 μΌλŠ”λ° 이 말은 무슨 말일까?

 

μžλ°” ν΄λž˜μŠ€λ‘œλ”λŠ” .class νŒŒμΌμ„ ν•œ λ²ˆμ— λͺ¨λ‘ 읽어 ν•„μš”ν•œ 의쑴 κ΄€κ³„μ˜ .class νŒŒμΌμ„ λΆˆλŸ¬μ˜€μ§€ μ•ŠλŠ”λ‹€.

 

ν΄λž˜μŠ€λ‘œλ”κ°€ νŒŒμΌμ„ 읽으며 ν•„μš”ν•œ μ‹œμ μ— λ™μ μœΌλ‘œ λ‘œλ“œν•˜κ³  μ΄λŠ” 즉, ν΄λž˜μŠ€κ°€ ν”„λ‘œκ·Έλž¨μ— μ˜ν•΄ 호좜될 λ•Œ κΉŒμ§€ λ‘œλ“œν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€.

 

μœ„μ™€ 같은 νŠΉμ„±μ€ λͺ‡κ°€μ§€κ°€ 더 μ‘΄μž¬ν•˜λŠ”λ° ν•˜λ‚˜μ”© μ•Œμ•„λ³΄λ„λ‘ ν•˜μž.

 

Java ClassLoader 의 νŠΉμ§•

 

Java Classloader, μžλ°” ν΄λž˜μŠ€λ‘œλ”λŠ” 3가지 λŒ€μ›μΉ™μ΄ μ‘΄μž¬ν•œλ‹€.

 

  1. Delegation
  2. Visibility
  3. Uniqueness

 

νŠΉμ§• 1, Deligation

 

ν΄λž˜μŠ€λ‘œλ”λŠ” ν•˜λ‚˜λ§Œ μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€.

 

ν΄λž˜μŠ€λ‘œλ”λŠ” 일반적으둜 μ—¬λŸ¬ 개의 ν΄λž˜μŠ€λ‘œλ”κ°€ μ‘΄μž¬ν•˜λ©° 각각의 ν΄λž˜μŠ€λ‘œλ”λŠ” ν•˜λŠ” 일이 μ •ν•΄μ Έμžˆλ‹€.

 

μ΄λŸ¬ν•œ ν΄λž˜μŠ€λ‘œλ”λ“€ μ‚¬μ΄μ˜ 관심사에 따라 처리λ₯Ό 할지 말지 κ²°μ •ν•˜λŠ” 것을 λ°”λ‘œ μœ„μž„ λͺ¨λΈ 이라고 ν•˜λ©° 계측 ꡬ쑰λ₯Ό λ°”νƒ•μœΌλ‘œ λ™μž‘ν•œλ‹€.

 

main() λ©”μ„œλ“œκ°€ μ‘΄μž¬ν•˜λŠ” ClassLoaderRunner ν΄λž˜μŠ€μ—μ„œ μ‚¬μš©μžκ°€ μ •μ˜ν•œ Internal 클래슀λ₯Ό λ‘œλ“œν•˜λŠ” 과정을 μœ„μž„, Delegation에 νλ¦„μœΌλ‘œ λ”°λΌκ°€λ³΄μž.

 

  • ClassLoaderRunner ν΄λž˜μŠ€λŠ” ApplicationClassLoader μ—κ²Œ Internal 클래슀λ₯Ό λ‘œλ“œν•˜λΌκ³  μš”μ²­ν•œλ‹€.
  • ApplicationClassLoader λŠ” 직접 λ‘œλ“œν•˜μ§€ μ•Šκ³  λΆ€λͺ¨μΈ ExtensionClassLoader μ—κ²Œ Internal 클래슀λ₯Ό λ‘œλ“œν•˜λΌκ³  μš”μ²­ν•œλ‹€.
  • μ—­μ‹œ ExtensionClassLoader λŠ” 직접 λ‘œλ“œν•˜μ§€ μ•Šκ³  λΆ€λͺ¨μΈ BootstrapClassLoader μ—κ²Œ Internal 클래슀λ₯Ό λ‘œλ“œν•˜λΌκ³  μš”μ²­ν•œλ‹€.
  • BootstrapClassLoader λŠ” rt.jar μ—μ„œ ν΄λž˜μŠ€κ°€ μ‘΄μž¬ν•˜λŠ”μ§€ ν™•μΈν•œλ‹€.
  • μžˆλ‹€λ©΄ 클래슀λ₯Ό λ‘œλ“œν•˜κ³  μ—†λ‹€λ©΄ ExtensionClassLoaderμ—μ„œ ApplicationClassLoader κΉŒμ§€ μ•žμ˜ 과정을 λ°˜λ³΅ν•œλ‹€.
  • λ§Œμ•½ μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ ClassNotFoundException 을 throw ν•œλ‹€.

 

νŠΉμ§• 2, Visibility

 

Visibility Principle 은 ν΄λž˜μŠ€λ‘œλ”μ˜ κ°€μ‹œλ²”μœ„λŠ” μƒμœ„ ν΄λž˜μŠ€λ‘œλ”λ§Œ 확인할 수 μžˆλ‹€λŠ” 것이닀.

 

더 ν’€μ–΄μ„œ μ΄μ•ΌκΈ°ν•˜μžλ©΄

 

ν•˜μœ„ ν΄λž˜μŠ€λ‘œλ”λŠ” μƒμœ„ ν΄λž˜μŠ€λ‘œλ”κ°€ λ‘œλ”©ν•œ 클래슀λ₯Ό 확인할 수 μžˆμ§€λ§Œ μƒμœ„ ν΄λž˜μŠ€λ‘œλ”λŠ” ν•˜μœ„ ν΄λž˜μŠ€λ‘œλ”κ°€ λ‘œλ”©ν•œ 클래슀λ₯Ό 확인할 수 μ—†λ‹€.

 

이 Visibility λ₯Ό 잘 μ§€μΌœμ•Όλ§Œ Java ClassLoader κ°€ λ˜λŠ”λ°, 이 μ œμ•½μ΄ λ°”λ‘œ λ‹€μŒμ— λ‚˜μ˜¬ Uniqueness 이닀.

 

νŠΉμ§• 3, Uniqueness

 

μœ μΌμ„±, Uniqueness 원칙은 Visibility 의 νŠΉμ„±μ„ μ΄μš©ν•΄μ„œ 클래슀의 Duplicate loading 을 막을 수 있게 λœλ‹€.

 

즉, ν•˜μœ„ ν΄λž˜μŠ€λ‘œλ”λŠ” μƒμœ„ ν΄λž˜μŠ€λ‘œλ”κ°€ λ‘œλ”©ν•œ 클래슀λ₯Ό λ‹€μ‹œ λ‘œλ”©ν•˜μ§€ μ•ŠλŠ” 것을 보μž₯ν•œλ‹€.

 

μ΄λŸ¬ν•œ μœ μΌμ„±μ„ 지킀기 μœ„ν•΄μ„œ Visibility 이외에도 Class Binary name을 μ΄μš©ν•˜λŠ”λ°, 이λ₯Ό FQCN, Fully Qualified Class Name 이라고 ν•œλ‹€.

 

이미 λ‘œλ“œλœ ν΄λž˜μŠ€μΈμ§€ ν™•μΈν•˜κΈ° μœ„ν•΄μ„œλŠ” Namespace 에 λ³΄κ΄€λœ FQCN을 κΈ°μ€€μœΌλ‘œ 클래슀λ₯Ό 찾아보고 μ—†λ‹€λ©΄ Delegation 을 ν†΅ν•΄μ„œ 클래슀λ₯Ό λ‘œλ“œν•œλ‹€.

 

ν΄λž˜μŠ€λ‘œλ”μ˜ μ’…λ₯˜

 

μœ„μ—μ„œ λ‚˜μ˜¨ Delegation λͺ¨λΈμ—μ„œ ApplicationClassLoader λ‚˜ BootstrapClassLoader 와 같이 잘 μ•Œλ €μ§„ ν΄λž˜μŠ€λ‘œλ”λ“€μ΄ μ‘΄μž¬ν•˜λŠ”λ°, λŒ€ν‘œμ μΈ JRE의 ν΄λž˜μŠ€λ‘œλ”λŠ” 3가지가 μžˆλ‹€.

 

 

  1. BootstrapClassLoader
  2. ExtensionClassLoader
  3. ApplicationClassLoader

 

이듀은 각각 λ‹€μŒκ³Ό 같은 역할을 μˆ˜ν–‰ν•œλ‹€.

 

  • Bootstrap Classloader
    • JVM을 기동할 λ–„ 생성됨.
    • Object 클래슀λ₯Ό λΉ„λ‘―ν•œ μžλ°” API λ₯Ό λ‘œλ“œν•˜λŠ” Classloader
  • Extension Classloader :
    • κΈ°λ³Έ μžλ°” APIλ₯Ό μ œμ™Έν•œ ν™•μž₯ ν΄λž˜μŠ€λ“€μ„ λ‘œλ“œν•˜λŠ” Classloader
  • User-Defined Class Loader :
    • μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ‚¬μš©μžκ°€ 직접 μ½”λ“œ μƒμ—μ„œ μƒμ„±ν•΄μ„œ μ‚¬μš©ν•˜λŠ” Classloader

 

λ‹€μŒ μ½”λ“œλ₯Ό μ°Έκ³ ν•΄λ³΄μž

 

public class Main {
    public static void main(String[] args) {
        System.out.println("μš°λ¦¬κ°€ μ •μ˜ν•œ 클래슀 : " + Main.class.getClassLoader()); // jdk.internal.loader.ClassLoaders$AppClassLoader
        System.out.println("Logging 클래슀 : "
        + Logging.class.getClassLoader()); // Logging:sun.misc.Launcher$ExtClassLoader
        System.out.println("Java Util에 ν¬ν•¨λœ 클래슀 " + String.class.getClassLoader()); // null
    }
}

 

μœ„μ˜ μ½”λ“œμ—μ„œ 3κ°€μ§€μ˜ λŒ€ν‘œμ μΈ ν΄λž˜μŠ€λ‘œλ”λ₯Ό λͺ¨λ‘ 확인할 수 μžˆλ‹€.

 

μœ„μ—μ„œ 3번째인 BootstrapClassLoader λŠ” 좜λ ₯ κ²°κ³Όκ°€ Null 둜 λ³΄μ΄λŠ”λ°, 이 μ΄μœ λŠ” Native C 둜 κ΅¬ν˜„μ΄ λ˜μ–΄μžˆκΈ° λ•Œλ¬Έμ— Java Runtime μ—μ„œ Loadλ₯Ό ν•  수 μ—†κΈ° λ•Œλ¬Έμ΄λ‹€.

 

ν΄λž˜μŠ€λ‘œλ”λŠ” 3가지 ν΄λž˜μŠ€λ‘œλ” 이외에도 μš°λ¦¬κ°€ 직접 λ§Œλ“€μ–΄μ„œ μ‚¬μš©ν•  수 μžˆλ‹€.

 

ClassLoaderκ°€ 클래슀λ₯Ό λ‘œλ“œν•˜λŠ” λ™μž‘ κ³Όμ •

 

μœ„μ—μ„œ λ³Έ νŠΉμ§•κ³Ό 원칙듀을 λ§Œμ‘±ν•˜λŠ” ν™˜κ²½μ—μ„œ ν΄λž˜μŠ€λ‘œλ”λŠ” λ‹€μŒκ³Ό 같은 과정을 거쳐 클래슀λ₯Ό λ‘œλ“œν•˜κ³  λ§ν¬ν•˜λ©° μ΄ˆκΈ°ν™”λ₯Ό ν•œλ‹€

 

 

  • λ‘œλ“œ Loading
    • Class file 을 κ°€μ Έμ™€μ„œ JVM의 λ©”λͺ¨λ¦¬μ— λ‘œλ“œν•œλ‹€.
  • 검증 Verifying
    • Java Language Specification 및 JVM λͺ…세에 μœ„λ°°λœ 정보가 μžˆλŠ”μ§€ κ²€μ‚¬ν•œλ‹€.
    • κ°€μž₯ λ³΅μž‘ν•˜κ³  μ‹œκ°„μ΄ μ˜€λž˜κ±Έλ¦¬λŠ” 뢀뢄이닀.
  • μ€€λΉ„ Preparing
    • ν΄λž˜μŠ€κ°€ ν•„μš”λ‘œν•˜λŠ” λ©”λͺ¨λ¦¬λ₯Ό ν• λ‹Ήν•œλ‹€.
    • ν΄λž˜μŠ€μ—μ„œ μ •μ˜λœ ν•„λ“œ, λ©”μ„œλ“œ, μΈν„°νŽ˜μ΄μŠ€λ₯Ό λ‚˜νƒ€λ‚΄λŠ” struct λ₯Ό μ€€λΉ„ν•œλ‹€.
  • 뢄석 Linking
    • 클래슀의 μƒμˆ˜ ν’€ λ‚΄ λͺ¨λ“  심볼릭 레퍼런슀λ₯Ό λ‹€μ΄λ ‰νŠΈ 레퍼런슀둜 λ³€κ²½ν•œλ‹€.
  • μ΄ˆκΈ°ν™” Initializing
    • 클래슀 λ³€μˆ˜λ“€μ„ μ μ ˆν•œ κ°’μœΌλ‘œ μ΄ˆκΈ°ν™”ν•œλ‹€.

 

κ²°λ‘ 

μš°λ¦¬λŠ” μ΄λ²ˆμ— ν΄λž˜μŠ€λ‘œλ”λž€ 무엇인가, ν΄λž˜μŠ€λ‘œλ”μ˜ νŠΉμ§• 및 원칙, ν΄λž˜μŠ€λ‘œλ”μ˜ λ™μž‘ κ³Όμ •, ν΄λž˜μŠ€λ‘œλ”μ˜ μ’…λ₯˜μ— λŒ€ν•΄μ„œ μ•Œμ•„λ³΄μ•˜λ‹€.

 

이런 ν΄λž˜μŠ€λ‘œλ”κ°€ 직접 ν΄λž˜μŠ€νŒŒμΌμ„ λΆˆλŸ¬λ“€μ΄κΈ° λ•Œλ¬Έμ— JVM은 직접적인 ν΄λž˜μŠ€μ™€ 연관이 생기지 μ•Šκ³  λ…λ¦½μ μœΌλ‘œ λ™μž‘ν•  수 있게 λ˜λŠ” 것이닀.

 

λŒ“κΈ€