達內–Java基礎進階——“ClassLoader之二——自定義ClassLoader” – JAVA編程語言程序開發技術文章

為什麼要使用自定義ClassLoader很多時候人們會選擇使用自定義的ClassLoader,而不使用系統的ClassLoader。這樣做的原因是,在編譯時無法預知運行時會需要哪些Class,特別是在一些AppServer中,比如Tomcat、Avalon-Phonix、Jboss;或是程序提供某種插件(Plug-In)的特性,讓用戶可以在隻擁有程序二進制代碼的情況下添加自己的功能,比如Ant、
 Jxta-shell等。

 

ClassLoader內部結構通常定制一個ClassLoader很簡單,一般隻需要很少的幾個步驟就可以完成。
 Java規范規定,所有的用戶自定義ClassLoader都必須從抽象類“java.lang.ClassLoader”類繼承而來。下面先看一下這個類的內部實現,以幫助我們更好的理解相關內容。

protected synchronized Class<?> loadClass(String name, boolean resolve)

    throws ClassNotFoundException

    {

    // First, check if the class has already been loaded

    Class c = findLoadedClass(name);

    if (c == null) {

     try {

        if (parent != null) {

         c = parent.loadClass(name, false);

        } else {

         c = findBootstrapClass0(name);

        }

     } catch (ClassNotFoundException e) {

     // If still not found, then invoke findClass in order

     // to find the class.

     c = findClass(name);

     }

    }

    if (resolve) {

     resolveClass(c);

    }

    return c;

    }
通常我們使用ClassLoader.loadClass(String
 name):Class根據指定的類名得到一個相應的Class實例。從Java源代碼中我們可以看到,缺省的ClassLoader做瞭如下的工作: 1. 調用FindLoadedClass(String):Class 檢查一下這個Class是否已經被加載過瞭。由於JVM 規范規定ClassLoader可以在緩存保留它所加載的Class,因此如果一個Class已經被加載過,直接從緩存中獲取即可。 2. 調用它的父類的LoadClass()方法,如果它的父類不為空,則使用JVM內部的ClassLoader(即著名的BootstrapClassloader)來加載這個Class。在第10行我們可以看到使用瞭一個Native方法來調用這個Bootstrap
 classloader。 3. 如果上面兩步都沒有找到,調用findClass(String):Class方法來查找並加載這個Class。 因此我們隻要覆蓋這個findClass(String):Class方法即可達到定義ClassLoader的要求。
1.FileClassLoader.java
package jack.classloader.own.local;

//Load local class file
import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.FileInputStream;

 

public class FileClassLoader extends ClassLoader {

   

    public Class<?> findClass(String name){

        byte [] data = loadClassData(name);

        return defineClass(name, data, 0, data.length);

    }

   

    private byte[] loadClassData(String name){

        FileInputStream fis = null;

        byte [] data = null;

        try {

            fis = new FileInputStream(

                new File(getFinalPath(name)));

            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            int ch = 0;

            while ((ch = fis.read()) != -1) {

                baos.write(ch);

            }

            data = baos.toByteArray();

        } catch (Exception e) {

            e.printStackTrace();

        }

        return data;

    }

   

    private String getFinalPath(String name){

        String finalPath = "";

        String path = System.getProperty("user.dir");

        String [] nameStrings = name.split("\\.");

        String tempStr = "";

        for(String str : nameStrings){

            tempStr = tempStr + str + File.separatorChar;

        }

        tempStr = tempStr.substring(0, tempStr.lastIndexOf(File.separatorChar));

        finalPath = path + File.separator + "bin" + File.separator + tempStr + ".class";

        return finalPath;

    }

}
2.RemoteClassLoader.java
package jack.classloader.own.remote;

 

 

//Looa remote class file

import java.io.InputStream;

 

import java.net.URL;

 

import java.net.URLConnection;

 

 

 

public class RemoteClassLoader extends ClassLoader {

 

   

 

    public Class<?> findClass(String name){

 

        byte [] data = loadClassData(name);

 

        name = "jack.classloader.test." + name;

 

        return defineClass(name, data, 0, data.length);

 

    }

 

   

 

    private byte[] loadClassData(String name){

 

        byte [] data = null;

 

        try {

 

            URL urlRemote = new URL("https:// www.aiwalls.com /test/" + name + ".class");//須保證遠程文件地址可達

 

 

            URLConnection uConnection = urlRemote.openConnection();

 

            InputStream inputStream = uConnection.getInputStream();

 

            int length = uConnection.getContentLength();

 

            data = new byte[length];

 

            inputStream.read(data);

 

            inputStream.close();

 

            return data;

 

        } catch (Exception e) {

 

            System.out.println(name +"類沒有找到!");

 

            e.printStackTrace();

 

        }

 

        return data;

 

    }

 

}
3.MyApp.java
package jack.classloader.own;

 

import jack.classloader.own.local.FileClassLoader;

import jack.classloader.own.remote.RemoteClassLoader;

import jack.classloader.test.IService;

 

public class MyApp {

 

    /**

     * @param args

     * @throws IllegalAcces***ception

     * @throws InstantiationException

     */

    @SuppressWarnings("unchecked")

    public static void main(String[] args) throws InstantiationException, IllegalAcces***ception {

        //local

        FileClassLoader loader = new FileClassLoader();

        Class<?> objClass = loader.findClass("jack.classloader.test.Service");

        IService service = (IService)objClass.newInstance();

        System.out.println(objClass.getName());

        System.out.println(objClass.getClassLoader());

        System.out.println(service);

        service.service();

       

        System.out.println();

        //remote

        RemoteClassLoader remoteLoader = new RemoteClassLoader();

        Class<?> objClassRemote = remoteLoader.findClass("Service");

        IService serviceRemote = (IService)objClassRemote.newInstance();

        serviceRemote.service();

    }

 

}

摘自 sdtarena

發佈留言