1. 程式人生 > >一個自定義的載入器

一個自定義的載入器

我們的自定義類載入器

  1. package cn.gd.cjz.class_loader;  
  2. import java.io.*;  
  3. import java.nio.ByteBuffer;  
  4. import java.nio.channels.FileChannel;  
  5. /** 
  6.  * 自定義類載入器 
  7.  */
  8. publicclass CustomClassLoader extends ClassLoader {  
  9.     /**類名**/
  10.     private String name;  
  11.     /**通過構造方法設定父類載入器和要熱載入的類名**/
  12.     public CustomClassLoader(ClassLoader parent , String name) {  
  13.         super(parent);  
  14.         if(name == null || name.length() <= 0)  
  15.             thrownew NullPointerException();  
  16.         this.name = name;  
  17.     }  
  18.     @Override
  19.     protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {  
  20.         Class<?> clazz = null
    ;  
  21.         /**如果是我們想要熱載入的類則呼叫我們重寫的findClass方法來載入**/
  22.         if(this.name.equals(name) && !"java".equals(name)){  
  23.             /**先看看要熱載入的類之前是否已經載入過了,因為一個類載入器只能載入一個類一次,載入多次會報異常**/
  24.             clazz = findLoadedClass(name);  
  25.             /**clazz==null說明之前沒有載入過**/
  26.             if(clazz == null)  
  27.                 clazz = findClass(name);  
  28.             /** 
  29.              * 類的生命週期包括:載入、驗證、準備、解析、初始化、使用、解除安裝。其中驗證、準備、解析統稱為連線 
  30.              * 如果要連線類 
  31.              */
  32.             if(resolve)  
  33.                 resolveClass(clazz);//如果類已連線過,resolveClass方法會直接返回
  34.             return clazz;  
  35.         }  
  36.         returnsuper.loadClass(name , resolve);  
  37.     }  
  38.     @Override
  39.     protected Class<?> findClass(String name) throws ClassNotFoundException {  
  40.         String fileName = c2f(name);  
  41.         byte[] bytes = f2b(fileName);  
  42.         return defineClass(name, bytes, 0, bytes.length);  
  43.     }  
  44.     /** 
  45.      * 類名轉為檔名 
  46.      * @param name 
  47.      * @return 
  48.      */
  49.     private String c2f(String name){  
  50.         /**編譯後的class檔案存放的目錄**/
  51.         String baseDir = "F:\\idea_workspace\\Test\\target\\classes\\";  
  52.         name = name.replace("." , File.separator);  
  53.         name = baseDir + name + ".class";  
  54.         return name;  
  55.     }  
  56.     /** 
  57.      * 讀取檔案byte陣列 
  58.      * @param fileName 
  59.      * @return 
  60.      */
  61.     privatebyte[] f2b(String fileName){  
  62.         RandomAccessFile file = null;  
  63.         FileChannel channel = null;  
  64.         byte[] bytes = null;  
  65.         try {  
  66.             /**隨機存取檔案物件,只讀取模式**/
  67.             file = new RandomAccessFile(fileName , "r");  
  68.             /**NIO檔案通道**/
  69.             channel = file.getChannel();  
  70.             /**NIO位元組緩衝**/
  71.             ByteBuffer buffer = ByteBuffer.allocate(1024);  
  72.             int size = (int) channel.size();  
  73.             bytes = newbyte[size];  
  74.             int index = 0;  
  75.             /**從NIO檔案通道讀取資料**/
  76.             while (channel.read(buffer) > 0){  
  77.                 /**位元組緩衝從寫模式轉為讀取模式**/
  78.                 buffer.flip();  
  79.                 while (buffer.hasRemaining()){  
  80.                     bytes[index] = buffer.get();  
  81.                     ++index;  
  82.                 }  
  83.                 /**位元組緩衝的readerIndex、writerIndex置零**/
  84.                 buffer.clear();  
  85.             }  
  86.         } catch (FileNotFoundException e) {  
  87.             e.printStackTrace();  
  88.         } catch (IOException e) {  
  89.             e.printStackTrace();  
  90.         }finally {  
  91.             if (channel != null) {  
  92.                 try {  
  93.                     channel.close();  
  94.                 } catch (IOException e) {  
  95.                     e.printStackTrace();  
  96.                 }  
  97.             }  
  98.             if (file != null) {  
  99.                 try {  
  100.                     file.close();  
  101.                 } catch (IOException e) {  
  102.                     e.printStackTrace();  
  103.                 }  
  104.             }  
  105.         }  
  106.         return bytes;  
  107.     }  
  108.     /** 
  109.      * 熱載入類 
  110.      * @return 
  111.      */
  112.     public Class<?> loadClass(){  
  113.         try {  
  114.             return loadClass(name);  
  115.         } catch (ClassNotFoundException e) {  
  116.             e.printStackTrace();  
  117.             returnnull;  
  118.         }  
  119.     }  
  120. }  

將要被熱載入的類介面
  1. package cn.gd.cjz.class_loader;  
  2. /** 
  3.  * 測試類介面 
  4.  */
  5. publicinterface IPrinter {  
  6.     publicvoid print();  
  7. }  

將要被熱載入的類
  1. package cn.gd.cjz.class_loader;  
  2. /** 
  3.  * 測試類 
  4.  */
  5. publicclass Printer implements IPrinter {  
  6.     @Override
  7.     publicvoid print() {  
  8.         System.out.println("彪悍的人生不需要解釋是誰說的?");  
  9.     }  
  10. }  

好了,寫個測試類來測試一下
  1. package cn.gd.cjz.class_loader;  
  2. import java.io.BufferedReader;  
  3. import java.io.IOException;  
  4. import java.io.InputStreamReader;  
  5. /*** 
  6.  * 自定義類載入器測試類 
  7.  */
  8. publicclass CustomClassTest {  
  9.     publicstaticvoid main(String[] args) {  
  10.         /**要進行熱載入的類名**/
  11.         String name = "cn.gd.cjz.class_loader.Print