首页 > 技术文章 > classLoader打破双亲委托机制

zheaven 2020-01-19 11:17 原文

思路:

通过重写loadClass方法将加载类的对象改为自定义类加载器

目标对象

package com.dwz.classLoader.chapter4;

public class SimpleObject {

}

类加载器对象

package com.dwz.classLoader.chapter4;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;

public class SimpleClassLoader extends ClassLoader{
    private final static String DEFAULT_DIR = "C:/Users/Administrator/Desktop/revert";
    
    private String dir = DEFAULT_DIR;
    
    private String classLoaderName;

    public SimpleClassLoader() {
        super();
    }
    
    public SimpleClassLoader(String classLoaderName) {
        super();
        this.classLoaderName = classLoaderName;
    }

    public SimpleClassLoader(String classLoaderName, ClassLoader parent) {
        //父委托
        super(parent);
        this.classLoaderName = classLoaderName;
    }
    
    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        Class<?> clazz = null;
        
        if(name.startsWith("java.")) {
            try {
                ClassLoader system = ClassLoader.getSystemClassLoader();
                clazz = system.loadClass(name);
                if(clazz != null) {
                    if(resolve) {
                        resolveClass(clazz);
                    }
                    return clazz;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        try {
            clazz = findClass(name);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        if(clazz == null && getParent() != null) {
            getParent().loadClass(name);
        }
        return clazz;
    }
    
    /**
     * @param name (xxx.xxx.xxx.xxx)
     *     xxx/xxx/xxx/xxx.class
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String classPath = name.replaceAll("\\.", "/");
        File classFile = new File(dir, (classPath + ".class"));
        if(!classFile.exists()) {
            throw new ClassNotFoundException("The class " + name + " not found under " + dir);
        }
        
        byte[] classBytes = loadClassBytes(classFile);
        if(null == classBytes || classBytes.length == 0) {
            throw new ClassNotFoundException("load the class " + name + " failed");
        }
        
        return this.defineClass(name, classBytes, 0, classBytes.length);
    }
    
    private byte[] loadClassBytes(File classFile) {
        try(ByteArrayOutputStream baos = new ByteArrayOutputStream();
                FileInputStream fis = new FileInputStream(classFile)) {
            byte[] buffer = new byte[1024];
            int len;
            while((len = fis.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            baos.flush();
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public String getDir() {
        return dir;
    }

    public void setDir(String dir) {
        this.dir = dir;
    }

    public String getClassLoaderName() {
        return classLoaderName;
    }
}

测试

package com.dwz.classLoader.chapter4;

public class SimpleClassLoaderTest {
    public static void main(String[] args) throws ClassNotFoundException {
        SimpleClassLoader simpleClassLoader = new SimpleClassLoader();
        Class<?> loadClass = simpleClassLoader.loadClass("com.dwz.classLoader.chapter4.SimpleObject");
        System.out.println(loadClass.getClassLoader());
    }
}

推荐阅读