jvm的傳唱-類載入
阿新 • • 發佈:2021-07-20
PS:承接上一篇文件,由於初次寫文件記錄類內容,對於部落格園目前的文件編譯不熟悉,第一篇文章寫的太不好看了,這次換了個模式 ,看看能好看點不,便於閱讀。
先通過程式碼看看類載入器的種類和效果
1 package com.bface.calculate; 2 3 /** 4 * @ClassName ClassLoaderLecode 5 * @Description TODO 6 * @Author cy 7 * @Date 2021/7/20 14:26 8 * @Version 1.0 9 */ 10 public class ClassLoaderLecode { 11View Codepublic static void main(String[] args) { 12 //獲取系統類載入器--> 它負責載入環境變數classpath或系統屬性java.class.path 指定路徑下的類 13 //庫 14 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); 15 System.out.println("系統類載入器"+ systemClassLoader); 16 //獲取擴充套件類載入器-->由sun.misc.Launcher$ExtClassLoader實現 2、從java.ext.dirs系統屬性所指定的目錄中載入類庫,17 //或從JDK的安裝目錄的jre/lib/ext 子目錄(擴充套件目錄)下載入類庫 18 ClassLoader parent = systemClassLoader.getParent(); 19 System.out.println("擴充套件類載入器"+parent); 20 //啟動類載入器-->這個類載入器使用c/c++實現,巢狀再jvm內部 2、它用來載入Java的核心類庫(JAVA_HOME/jre/lib/rt.jar、 resource.jar或sun.boot.class.path路徑下的內容),用於提供JVM自身需要的類21 ClassLoader parent1 = parent.getParent(); 22 System.out.println("啟動類載入器"+parent1); 23 24 //獲取使用者自定的類的類預設類載入器 25 ClassLoader classLoader = ClassLoaderLecode.class.getClassLoader(); 26 System.out.println("自定義類的類載入器"+classLoader); 27 } 28 29 }
為什麼要使用這種模式呢,這裡簡單說兩句,1.保障同一個型別 尤其是底層庫類的唯一性,防止非法篡改,在jvm中判斷一個物件的型別是與類載入器有關的,不同的類載入器即便對於開發人員來說一樣的物件程式碼,表示出來的型別也是不一樣的,所以還是能區別出來。
如何實現自定義的類載入器呢,每次通過先委託父類載入器載入,當父類載入器無法載入時,再自己載入。其實 ClassLoader 類預設的 loadClass 方法已經幫我們寫好了,我們無需去寫。
有的小夥伴可能會疑問,為什麼要自定義類載入器,平時開發好像沒怎麼用到,有啥用呢?我總結自己覺得可能用到的地方,有的地方寫的第三方jar包需要給別人使用,為了保障程式碼相對安全不被輕易解讀,可以通過自定義類載入器在載入時進行加密處理,這樣相對來說吧 是能解決安全問題的。
開始編寫自定義類載入器程式碼如下,大家可以參考借鑑
1 package com.bface.calculate; 2 3 import javax.jnlp.ExtendedService; 4 import java.io.BufferedInputStream; 5 import java.io.ByteArrayOutputStream; 6 import java.io.FileInputStream; 7 import java.io.IOException; 8 import java.util.Calendar; 9 10 /** 11 * @ClassName ClassLoaderLecode 12 * @Description TODO 13 * @Author cy 14 * @Date 2021/7/20 14:26 15 * @Version 1.0 16 */ 17 public class ClassLoaderLecode { 18 public static void main(String[] args) { 19 //獲取系統類載入器--> 它負責載入環境變數classpath或系統屬性java.class.path 指定路徑下的類 20 //庫 21 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); 22 System.out.println("系統類載入器" + systemClassLoader); 23 //獲取擴充套件類載入器-->由sun.misc.Launcher$ExtClassLoader實現 2、從java.ext.dirs系統屬性所指定的目錄中載入類庫, 24 //或從JDK的安裝目錄的jre/lib/ext 子目錄(擴充套件目錄)下載入類庫 25 ClassLoader parent = systemClassLoader.getParent(); 26 System.out.println("擴充套件類載入器" + parent); 27 //啟動類載入器-->這個類載入器使用c/c++實現,巢狀再jvm內部 2、它用來載入Java的核心類庫(JAVA_HOME/jre/lib/rt.jar、 resource.jar或sun.boot.class.path路徑下的內容),用於提供JVM自身需要的類 28 ClassLoader parent1 = parent.getParent(); 29 System.out.println("啟動類載入器" + parent1); 30 31 //獲取使用者自定的類的類預設類載入器 32 ClassLoader classLoader = ClassLoaderLecode.class.getClassLoader(); 33 System.out.println("自定義類的類載入器" + classLoader); 34 35 36 ClassLoaderLecode classLoaderLecode = new ClassLoaderLecode(); 37 try { 38 ZdyClassLoader zdyClassLoader = classLoaderLecode.new ZdyClassLoader("D:\\IdeaProjects\\leecode\\out\\production\\leecode\\com\\bface\\calculate\\"); 39 Class<?> arrayLecode = zdyClassLoader.loadClass("ArrayLecode"); 40 System.out.println("我是由" + arrayLecode.getClassLoader().getClass().getName() + "類載入器載入的"); 41 42 } catch (ClassNotFoundException e) { 43 e.printStackTrace(); 44 } 45 } 46 47 class ZdyClassLoader extends ClassLoader { 48 private String codePath; 49 50 public ZdyClassLoader(ClassLoader parent, String codePath) { 51 52 } 53 54 public ZdyClassLoader(String codePath) { 55 this.codePath = codePath; 56 57 } 58 59 @Override 60 protected Class<?> findClass(String name) throws ClassNotFoundException { 61 BufferedInputStream bis = null; 62 ByteArrayOutputStream baos = null; 63 try { 64 65 //1.位元組碼路徑 66 String fileName = codePath + name + ".class"; 67 //2.獲取輸入流 68 bis = new BufferedInputStream(new FileInputStream(fileName)); 69 //3.獲取輸出流 70 baos = new ByteArrayOutputStream(); 71 //4.io讀寫 72 73 int len; 74 byte[] data = new byte[1024]; 75 while ((len = bis.read(data)) != -1) { 76 baos.write(data, 0, len); 77 } 78 //5.獲取記憶體中位元組陣列 79 byte[] byteCode = baos.toByteArray(); 80 //6.呼叫defineClass 將位元組陣列轉成Class物件 81 Class<?> defineClass = defineClass(null, byteCode, 0, byteCode.length); 82 return defineClass; 83 } catch (IOException e) { 84 e.printStackTrace(); 85 } finally { 86 try { 87 if (bis != null) { 88 bis.close(); 89 } 90 if (baos != null) { 91 baos.close(); 92 } 93 } catch (IOException e) { 94 e.printStackTrace(); 95 } 96 } 97 return null; 98 } 99 } 100 101 }View Code
"C:\Program Files\Java\jdk1.8.0_66\bin\java.exe" -Dvisualvm.id=603520010088200 "-javaagent:D:\ProgramSoft\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=63737:D:\ProgramSoft\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_66\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\rt.jar;D:\IdeaProjects\leecode\out\production\leecode" com.bface.calculate.ClassLoaderLecode
系統類載入器sun.misc.Launcher$AppClassLoader@14dad5dc
擴充套件類載入器sun.misc.Launcher$ExtClassLoader@1b6d3586
啟動類載入器null
自定義類的類載入器sun.misc.Launcher$AppClassLoader@14dad5dc
我是由com.bface.calculate.ClassLoaderLecode$ZdyClassLoader類載入器載入的