類加載器層次結構(由高到低)
1.引導類加載器 bootstrap class loader
做用:用來加載java的核心庫JAVA_HOME/jre/lib/rt.jar,不繼承自java.lang.ClassLoader
2.擴展類加載器 extensions class loader
做用:Java虛擬機的實現回提供一個擴展目錄,該類加載器在此目錄裏面查找並加載java類
3.應用程序類加載器 application class loader
做用:通常java應用類都是由它來完成
4.自定義類加載器
做用:實現本身的類加載器,以知足一些特殊要求
繼承java.lang.ClassLoader類
自定義文件加載器:java
1 import java.io.ByteArrayOutputStream; 2 import java.io.FileInputStream; 3 import java.io.FileNotFoundException; 4 import java.io.IOException; 5 import java.io.InputStream; 6 7 /** 8 * 自定義文件類加載器 9 * 1.繼承java.lang.ClassLoader 10 * @author Nicotine 11 * 12 */ 13 public class FileSystemClassLoader extends ClassLoader { 14 //com.sansan.test.User 在D:/test/讀取 15 //文件路徑 16 private String rootDir; 17 18 public FileSystemClassLoader(String rootDir) { 19 this.rootDir = rootDir; 20 } 21 @Override 22 protected Class<?> findClass(String name) throws ClassNotFoundException { 23 24 Class<?> c = findLoadedClass(name); 25 26 //先查看有沒有加載過這個類,若是已經加載過了,則直接返回;若是沒有,則加載新的類 27 if (null!=c) { 28 return c; 29 }else { 30 //雙親模式:獲取父類加載器, 31 ClassLoader parent = this.getParent(); 32 try { 33 c = parent.getClass(); 34 } catch (Exception e) { 35 } 36 } 37 if (null!=c) { 38 return c; 39 }else { 40 byte[] classData = getClassData(name); 41 if (null==classData) { 42 throw new ClassNotFoundException(); 43 }else{ 44 c=defineClass(name, classData, 0,classData.length); 45 } 46 } 47 return c; 48 } 49 private byte[] getClassData(String classname) { 50 //源數據路徑 51 String path = rootDir + "/"+classname.replace(".","/")+".class"; 52 //讀取 53 //IOUtils,能夠使用它將IO流的數據轉換成字節數組 54 //選擇流 55 InputStream is = null; 56 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 57 58 try { 59 is=new FileInputStream(path); 60 byte[] buffer = new byte[1024]; 61 int temp = 0; 62 //讀取 63 while ((temp=is.read(buffer))!= -1) { 64 baos.write(buffer,0,temp); 65 } 66 return baos.toByteArray(); 67 } catch (FileNotFoundException e) { 68 e.printStackTrace(); 69 return null; 70 } catch (IOException e) { 71 e.printStackTrace(); 72 return null; 73 }finally{ 74 if (is!=null) { 75 try { 76 is.close(); 77 } catch (IOException e) { 78 e.printStackTrace(); 79 } 80 } 81 if (baos!=null) { 82 try { 83 baos.close(); 84 } catch (IOException e) { 85 e.printStackTrace(); 86 } 87 } 88 } 89 } 90 }
測試代碼:bootstrap
public class TestFileClass { public static void main(String[] args) throws ClassNotFoundException { FileSystemClassLoader loader = new FileSystemClassLoader("D:/test"); Class<?> c = loader.loadClass("com.sansan.test.HelloWorld"); System.out.println(c.hashCode()); } }
運行輸出類的哈希值數組
java.lang.ClassLoader類
根據一個指定的類的名稱,找到或者生成其對應的字節碼,而後從這些字節碼中定義一個java類,級java.lang.Class的一個實例
相關方法
getParent() 返回該類加載器的父類加載器
loadClass(String name) 加載名稱爲name的類,返回結果就是java.lang.Class類的實例
findClass(String name) 查找名稱爲name的類,返回結果就是java.lang.Class類的實例
findLoadedClass(String name) 查找名稱爲name的已經被加載過的類,返回結果就是java.lang.Class類的實例
defineClass(String name,byte[] b,int off,int len)把字節數組b中的內容轉換成java類,返回結果就是java.lang.Class類的實例
resolveClass(Class<?> c)連接指定的Java類
通常採用代理模式
交給其它加載器來加載指定的類
雙親委託機制
父類加載器優先加載
爲了保證java核心庫的類型安全
這種機制就保證不會出現用戶本身能定義java.lang.Object類的狀況
雙親委託機制是代理模式的一種
並非全部的類加載器都採用雙親委託機制
Tomcat服務器加載器也是用代理模式,所不一樣的是它首先嚐試去加載某各種,若是找不到在代理給父類加載器,這與通常的加載器順序相反
安全