Java Classloader

来源:互联网 发布:破解八零网络验证 编辑:程序博客网 时间:2024/04/27 06:36

Java类装载器可分为Bootrap类装载器,扩展类装载器,应用类装载器,自定义类装载器。其中,根类装载器和扩展类装载器是不能直接控制的,应用类装载器和自定义装载器则可以用来自行装载类。

应用类装载器将类装载到应用类Classloader中,而自定义类装载器将类装载到自定义(如使用URLClassloader)中,不同的自定义Classloader装载同样的Class,具有独立的内存空间,即使是类中的静态变量,也是相互隔离,不受对方赋值操作的影响。

1、一个应用类装载器的例子:

    /**     * 装载jar文件     * @param file     * @throws Exception     */    public static void loadJar(String file) throws Exception {            JarFile jar = new JarFile(file);        Enumeration<JarEntry> entries = jar.entries();                ClassLoader cl = (ClassLoader) Thread.currentThread().getContextClassLoader();                //获取ClassLoader类的defineClass(String, byte[], int, int) 方法,对protected类型修改访问权限        Method md1 = java.lang.ClassLoader.class.getDeclaredMethod("defineClass",                 String.class, byte[].class,    int.class, int.class);                md1.setAccessible(true);        String name;        // 装载所有的jar文件        while (entries.hasMoreElements()) {            JarEntry entry = entries.nextElement();                        if (entry.getName().endsWith(".class")) {                name = entry.getName();                name = name.substring(0, name.length() - 6);                name = name.replaceAll("/", ".");                 InputStream is = jar.getInputStream(entry);                ByteArrayOutputStream dataOut = new ByteArrayOutputStream();                 byte[] packData = new byte[2048];                int readLen = 0;                                while (-1 != (readLen = is.read(packData))) {                    dataOut.write(packData, 0, readLen);                }                                if (dataOut.size() <= 0) {                    throw new ClassNotFoundException(name);                }                byte[] classFile = dataOut.toByteArray();                                System.out.println("class name:" + name);                md1.invoke(cl, name, classFile, 0, classFile.length);            }        }    }            /**     *      */    public void loadTest(){        String file = "D:\\test2\\TestedClass.jar";                try {            ClassLoaderTest.loadJar(file);                        Class<?> c = Class.forName("dictquery.Hello");            Method[] ms = c.getDeclaredMethods();            Object obj = c.newInstance();                        for(int i=0;i<ms.length;i++){                Method m = ms[i];                System.out.println("Method:" + m.getName());                m.invoke(obj, new Object[]{});            }                        Field[] fs = c.getDeclaredFields();            for (int i = 0; i < fs.length; i++) {                Field f = fs[i];                                System.out.println("Field:" + f.getName() + ", Modifier:" + f.getModifiers());                                if((Modifier.PUBLIC+ Modifier.STATIC) == f.getModifiers()){                    System.out.println("Used public and static qualify!");                }                                //改变可访问属性                f.setAccessible(true);                try {                    String value = (String)f.get(obj);                    System.out.println("Field " + f.getName() + " default value:" + value);                } catch (Exception e) {                    e.printStackTrace();                }                            }                    } catch (Exception e) {            e.printStackTrace();        }            }        /**     *      * @param args     */    public static void main(String[] args) {        ClassLoaderTest ct = new ClassLoaderTest();        ct.loadTest();    }

该方法装载类后,类的内存空间在应用装载类中。

2、一个自定义类装载器的例子:

import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;public class FileSystemClassLoader extends ClassLoader {private String rootDir;public FileSystemClassLoader(String rootDir) {this.rootDir = rootDir;}protected Class<?> findClass(String name) throws ClassNotFoundException {byte[] classData = getClassData(name);if (classData == null) {throw new ClassNotFoundException();}else {return defineClass(name, classData, 0, classData.length);}}private byte[] getClassData(String className) {String path = classNameToPath(className);try {InputStream ins = new FileInputStream(path);ByteArrayOutputStream baos = new ByteArrayOutputStream();int bufferSize = 4096;byte[] buffer = new byte[bufferSize];int bytesNumRead = 0;while ((bytesNumRead = ins.read(buffer)) != -1) {baos.write(buffer, 0, bytesNumRead);}return baos.toByteArray();} catch (IOException e) {e.printStackTrace();}return null;}private String classNameToPath(String className) {return rootDir + File.separatorChar+ className.replace('.', File.separatorChar) + ".class";}}
该类装载器装载类后,类的运行空间在自定义Classloader中,对两个使用上述
FileSystemClassLoader 
或URLClassloadeer而言,对同一类,在不同的Classloader中是相互隔离的,互不受干扰。

3、自定义类装载器测试

使用URLClassloader装载:

/** * 类装载到自定义类装载器,分别使用不同的自定义装载器装载 */public void classLoadTest3c(){try {URL[] urls = new URL[]{ new File("D:\\Users\\workspace\\ClassLoadTest\\bin").toURI().toURL() };ClassLoader clsLoader = new URLClassLoader(urls);Class<?> c1 = clsLoader.loadClass("test.ClassLoaderTest");Field f = c1.getDeclaredField("testVar");Method m = c1.getMethod("showTestVar", null);Object obj = c1.newInstance();m.invoke(obj, new Object[]{});f.set(obj, "The testVar's value is modified!");m.invoke(obj, new Object[]{});System.out.println("--------------------");System.out.println(this.getClass().getClassLoader());ClassLoader clsLoader2 = new URLClassLoader(urls);System.out.println(clsLoader2.getSystemClassLoader());Class<?> c2  = clsLoader2.loadClass("test.ClassLoaderTest");Object obj2 = c2.newInstance();Method m2 = c2.getMethod("showTestVar", null);m2.invoke(obj2, new Object[]{});m.invoke(obj, new Object[]{});m2.invoke(obj2, new Object[]{});} catch (Exception e) {e.printStackTrace();}}

ClassLoaderTest.java, 参见1.

4、在已有的自定义类装载器中装载

/** * 类装载到自定义类装载器,共用一个自定义类装载器 */public void classLoadTest3d(){try {URL[] urls = new URL[]{ new File("D:\\Users\\workspace\\ClassLoadTest\\bin").toURI().toURL() };ClassLoader clsLoader = new URLClassLoader(urls);Class<?> c1 = clsLoader.loadClass("test.ClassLoaderTest");Field f = c1.getDeclaredField("testVar");Method m = c1.getMethod("showTestVar", null);Object obj = c1.newInstance();m.invoke(obj, new Object[]{});f.set(obj, "The testVar's value is modified!");m.invoke(obj, new Object[]{});System.out.println("--------------------");System.out.println(this.getClass().getClassLoader());ClassLoader clsLoader2 = new URLClassLoader(urls, clsLoader);System.out.println(clsLoader2.getSystemClassLoader());Class<?> c2  = clsLoader2.loadClass("test.ClassLoaderTest");Object obj2 = c2.newInstance();Method m2 = c2.getMethod("showTestVar", null);m2.invoke(obj2, new Object[]{});m.invoke(obj, new Object[]{});m2.invoke(obj2, new Object[]{});} catch (Exception e) {e.printStackTrace();}}
clsLoader2使用clsLoader 的Classloader,因而,clsLoader2的类"test.ClassLoaderTest" 使用clsLoader中的"test.ClassLoaderTest"

5、注意,这些测试的类均不要放置在当前项目的类路径底下。否则因为Bootrap类装载器会自动装载,再行加载已加载的类无效。

6、




原创粉丝点击