1. 程式人生 > 其它 >jvm的傳唱-類載入

jvm的傳唱-類載入

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 {
11
public 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 }
View Code

為什麼要使用這種模式呢,這裡簡單說兩句,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類載入器載入的