Tìm hiểu về Java Class Loader

Java ClassLoader tiến hành nạp một tệp class của java vào máy ảo (JVM). Chỉ đơn giản là như vậy. Đây không phải là khái niệm lớn và phức tạp để hiểu được và mọi nhà phát triển java phải biết về Java Class Loader (bộ nạp lớp java) và cách thức hoạt động của nó.

Có một ngoại lệ (exception) phố biến không kém NullPointerException đó là ClassNotFoundException. Trong giai đoạn đầu làm việc với Java bạn có thể sẽ gặp vô số ClassNotFoundException. Java Class Loader là thủ phạm gây ra ngoại lệ này.

Các loại (phân cấp) Java Class Loader

Java Class Loader có thể được phân loại như sau:

Bootstrap Class Loader (Bộ nạp Lớp Khởi động)

Bootstrap Class Loader nạp các lớp java căn bản (core class) thuộc các gói như java.lang, java.util, v.v.. Những lớp này là một phần của môi trường thực thi của java (JRE). Bootstrap Class Loader được triển khai riêng cho từng nền tảng nên có thể khác nhau giữa các JVM.

Extensions Class Loader (Bộ nạp Lớp Mở rộng)

Thư mục JAVA_HOME/jre/lib/ext chứa các gói jar, đây là những lớp java mở rộng cho các lớp java cơ bản. “Extensions class loader” nạp các lớp java từ thư mục “ext” này. Bạn có thể sử dụng thuộc tính môi trường hệ thống java.ext.dirs để bổ sung thêm các thư mục “ext” và các tệp jar cho Extensions Class Loader nạp vào JVM.

System Class Loader (Bộ nạp Lớp Hệ thống)

Các lớp java có sẵn trong classpath của java được nạp bởi “System class loader”

Bạn có thể thấy nhiều loại Class Loader khác như java.net.URLClassLoader, java.security.SecureClassLoader, v.v.. Chúng là những bộ nạp mở rộng từ java.lang.ClassLoader.

Các Class Loader có mối quan hệ phân cấp với nhau. Class Loader có thể nạp các lớp từ một cấp độ nào đó trên hệ thống phân cấp của chúng. Mức thứ nhất là Bootstrap Class Loader, mức thứ hai là Extensions Class Loader và mức thứ ba là System Class Loader.

Lớp tự tham chiếu

Khi trình biên dịch tiến hành biên dịch một tệp mã nguồn java sang định dạng binary class, nó chèn một thuộc tính vào trong tệp tin class này. Đây là một trường “public final” được đặt tên là “class” với kiểu dữ liệu java.lang.Class

Do đó với tất cả các lớp java bạn đều có thể truy xuất thuộc tính này như sau: java.lang.Class classObj = ClassName.class;

Sự quan trọng của đối tượng Class đó là nó có phương thức getClassLoader() để trả về một “class loader” cho một lớp. Phương thức này sẽ trả về null nếu nó đã được nạp bởi “bootstrap class loader”.

Java Class Loader làm việc như thế nào?

Khi một tên lớp được gửi tới, trước hết “class loader” sẽ xác định xem lớp đó ở đâu và sau đó đọc tệp class có tên gọi đó từ hệ thống tệp bản địa. Do đó, quá trình nạp này phụ thuộc vào nền tảng (platform).

Mặc định java.lang.ClassLoader đã được đăng ký như là một class loader có khả năng nạp song song các lớp. Nhưng các lớp con cần phải được đăng ký là song song hoặc không tại thời điểm khởi tạo.

Các lớp cũng có thể được nạp từ mạng, được tạo ra trong thời gian chạy và nạp. Lớp ClassLoader có một phương thức tên là defineClass với đầu vào là mảng byte và nạp vào một lớp.

Cha của Class Loader

Tất cả các “class loader” ngoại trừ “bootstrap class loader” đều có một “class loader” cha. Lớp cha này không giống như trong quan hệ cha-con của kế thừa. Mọi thể hiện của “class loader” được kết hợp với một “class loader” cha.

Khi một “class loader” được giao phó trách nhiệm nạp một lớp, bước đầu tiên nó trao công việc này cho một “class loader” cha đã được kết hợp cho nó. Sau đó, “class loader” cha nhận được hướng dẫn và tiếp tục trao lời gọi tới “class loader” cha của nó. Trong dãy phân cấp này, Bootstrap Class Loader có vị trí cao nhất.

Khi một thể hiện của “class loader” được tạo ra, nó sử dụng hàm dựng để “class loader” cha có thể kết hợp với nó.

Class Loader: Quy tắc 1

Một lớp được nạp chỉ một lần vào JVM.

Trong quy tắc này, “một lớp” là gì? Tính duy nhất của một lớp được xác định cùng với đối tượng ClassLoader mà đã nạp nó vào JVM. Một lớp luôn được xác định sử dụng tên đầy đủ của nó (package.classname). Vì vậy, bạn sẽ có một entry (tên gói, tên lớp, class loader) khi một lớp được nạp vào JVM. Do đó, cùng một lớp có thể được nạp hai lần bởi hai đối tượng ClassLoader khác nhau.

Người dịch: Nguyễn Việt Khoa – Tạp chí lập trình