Java ClassLoader คืออะไร

Sakul Montha
3 min readJan 23, 2019

--

Java ClassLoader

เป็นที่ทราบกันอยู่แล้วว่า Java นั้นรันบน JVM (Java Virtual Machine) เมื่อเรา Compile Java class มันจะแปลงร่างเป็น bytecode แล้วเก็บไฟล์เป็น “.class” หลังจากนั้น เมื่อเราต้องการใช้ class ตัว Java class loader จะทำการโหลดคลาสนั้น ๆ ลงใน Memory…

บทความนี้จะอธิบายแบบผิว ๆ นะครับไม่เจาะลึกลงไปว่า
Load ลง Memory แล้วมันจะไปอยู่ไหน หรือ JVM Memory Model
ไม่ว่าจะเป็น Metaspace, Code Cache, Eden space, etc. ก็ไม่พูดถึง

Mahasak Pijittum ได้กล่าวไว้ว่า เด็กสมัยนี้เกิดมาในยุค RAM ถูก CPU ไม่แพง ไม่เคยได้ tuning JVM เอง เลยไม่รู้ว่าจริง ๆ แล้วเบื้องหลังมันทำงานอะไรยังไง

ก่อนจะเข้าเรื่อง “รู้หรือไม่ Kotlin, Scala, Groovy, Clojure ล้วนแล้วแต่รันบน JVM ฮ่า ๆ ขายของเก่ง”

ClassLoader Subsystem

ClassLoader subsystem ถือเป็น Core ของ JVM ที่ใช้ในการ loading/reading “.class” ไฟล์

ในส่วนของ ClassLoader Subsystem ได้ถูกแบ่งออกเป็น 3 ส่วน Loading, Linking และ Initialization

Loading

เราแบ่ง Loading build-in ClassLoader ใน Java ออกเป็น 3 ประเภท

  1. Bootstrap ClassLoader – โหลดคลาสจาก internal JDK โดยทั่วไปมันมักจะโหลดมาจากคลาสหลัก ๆ ทั่วไป เช่น “java.lang.*” หรือพวก “package class” $JAVA_HOME/lib/rt.jar
  2. Extensions ClassLoader – โหลดคลาสจาก extensions JDK directory โดยมากจะโหลดมาจาก $JAVA_HOME/lib/ext
  3. Application or System ClassLoader – โหลดคลาสจาก classpath ปัจจุบัน โดยที่สามารถ invoke classpath ได้ด้วย command -cp หรือ -classpath

ใครไม่รู้จัก classpath แนะนำให้ไปอ่านก่อน พักหลังผมมักเจอว่า เหล่านักพัฒนาซอฟแวร์เรา ไม่รู้จักกันหลายคน

Linking

ในส่วนนี้จะเป็นการทำ Linking class หรือพวก interface ที่เกี่ยวข้องเพื่อที่จะ allocation new data structure โดยแบ่งเป็น 3 หมวดย่อย Verification, Preparation, Resolution

Initialization

ส่วนนี้จะเป็นกระบวนการขั้นสุดท้ายของ Class loading ตัวแปรต่าง ๆ จะถูกกำหนดค่า และถูกเรียกจากคลาสแม่ ไปยังคลาสลูก

Java Class Loading in JVM

How ClassLoader Work

ClassLoader เป็นส่วนหนึ่งของ JRE (Java Runtime Environment) เมื่อตัว JVM ทำการ Request class ตัว Class Loader จะทำการวิ่งไปหา class แล้วนำตัว class เข้าไปสู่ runtime ถ้าหากไม่สามารถโหลดคลาสได้ มันจะทำการ request ไปยังคลาสแม่ไปเรื่อย ๆ ถ้าหากหายังไงก็หาไม่เจอ… เราก็จะได้เห็นภาพคุ้นตาครับ java.lang.NoClassDefFoundError ไม่ก็ java.lang.ClassNotFoundException นั่นเอง

java.lang.NoClassDefFoundError เกิดขึ้นเมื่อ Java runtime system พยายามจะ load definition ของ class แต่ไม่สามารถใช้งานได้

java.lang.ClassNotFoundException เกิดขึ้นเมื่อ application พยายามโหลด Class ที่ runtime Class.forName() หรือ loadClass() หรือ findSystemClass() ใน classpath ไม่เจอ

เอาไว้คราวหน้าจะเล่าแบบละเอียดแต่ถ้าอยากศึกษาก่อน แนะนำให้ไปอ่านได้ ที่นี่ ครับ

Delegation Model

เป็นการมอบหมายงาน เมื่อมีการ Request application class ไปสู่ JVM ตัว JVM จะทำการ เรียก System ClassLoader จากนั้นก็จะไปเรียก Extension ClassLoader แล้วก็ไปที่ Bootstrap ClassLoader

JVM -> System ClassLoader -> Extension ClassLoader -> Bootstrap ClassLoader

Uniqueness

ในส่วนนี้เป็นผลต่อเนื่องมาจาก Delegation model ตัว Class ที่ถูก load มาแล้วนั้น ไม่ควรถูกโหลดอีกครั้งโดย Child Class Loader

Visibility

ตัว Children ClassLoader จะมองเห็นได้แค่ ตัว Parent Class Loader เท่านั้น

ตัวอย่างเช่น ถ้า Class A ถูกโหลดมาจาก Application class loader และ Class B โหลดจาก Extention class loader ทั้ง Class A และ Class B ก็จะปรากฎให้เห็นเช่นกัน แต่ว่า Class B จะมองเห็นได้แค่เฉพาะ Extension class loader ที่เกี่ยวข้องกันเท่านั้น

เพื่อให้เข้าใจมากขึ้น เรามาดูรูปกันดีกว่าตัวอย่าง: JVM ทำการ Request Customer.class

  1. มันจะวิ่งไปที่ System ClassLoader ตัว System ClassLoader จะทำการมอบหมายไปให้กับ Extension ClassLoader จากนั้นก็ส่งไปยัง Bootstrap ClassLoader
  2. Bootstrap ClassLoader ทำการ Load Customer.class ถ้าเจอก็จะทำการ Load to memory
  3. ในกรณีที่ Bootstrap ClassLoader หา Customer.class ไม่เจอ ตัว Extension ClassLoader ก็จะทำการหาจาก $JAVA_HOME/jre/ext ถ้าเจอก็จะทำการ Load to memory
  4. ในกรณีที่ Extension Class Loader หา Customer.class ไม่เจอ ตัว System ClassLoader ก็จะทำการหาเองจาก classpath ถ้าเจอก็จะทำการ Load to memory
  5. ในกรณีที่ System ClassLoader หา Customer.class ไม่เจออีก เราก็จะได้เห็นภาพคุ้นตา “java.lang.ClassNotFoundException”
ตัวอย่างการทำงาน

Conclusion

สรุปสั้น ๆ ได้ว่า ClassLoader Subsystem แบ่งออกได้ 3 ส่วน Loading, Linking และ Initialzation

ใน Loading ตัว Java ClassLoader แบ่งออกเป็น 3 ส่วน

  • Bootstrap ClassLoader เอาของจาก $JAVA_HOME/lib/rt.jar
  • Extension ClassLoader เอาของจาก $JAVA_HOME/lib/ext
  • Application or System ClassLoader เอาของจาก classpath

ใน Linking แบ่งออกเป็น 3 ส่วน Verification, Preparation, Resolution

ผมได้รับแรงบันดารใจในการเขียนเรื่องนี้มาจาก น้องในทีมเดินมาบอกว่า พี่กิ๊กครับ ผมอยากอ่าน Java ClassLoader ถ้าพี่เขียนผมสัญญาว่าผมจะอ่านทุกบรรทัด (ในใจผมคิดว่าแล้วทำไมไม่หาอ่านเองงงงงง 5555) แต่ก็ถือเป็นเรื่องดีที่ได้ทบทวน แล้วก็ได้แบ่งปันเรื่องราวนี้สู่มวลมนุษยชาติ

อันที่จริงมันยังมี JIT Complier, Hotspot, Hot Reload อีกที่ไม่ได้กล่าวถึง… ที่เป็นเหตุผลว่า… ทำไม JAVA เร็วส์ ครั้งหน้าผมอาจจะมาต่อในส่วนของ Custom ClassLoader

หากอ่านถึงตรงนี้ยังคาใจ ไปอ่านต่อที่ References ด้านล่างต่อกันได้เลย

References

--

--

Sakul Montha
Sakul Montha

Written by Sakul Montha

Chief Product Officer, a man who’s falling in love with the galaxy.

No responses yet