美文网首页
自定义类加载器

自定义类加载器

作者: LorenzoKing | 来源:发表于2017-11-24 23:43 被阅读0次

    The default implementation of this method searches for classes in the following order:

    1. Invoke findLoadedClass(String) to check if the class has already been loaded.
    2. Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.
    3. Invoke the findClass(String) method to find the class.

    稍微理解下:

    1. 首先调用findLoadedClass(String),如果被加载过直接返回true,没有执行下一个步骤
    2. 调用父级类加载器的loaderClass方法,如果父级类加载器为空,就使用JVM默认的类加载器
    3. 调用findClass方法

    这个是模版方法设计模式的运用。

    编写自定义类加载器

    需要继承ClassLoader类,重写findClass方法。

    package lorenzo;
    public class MyClassLoader extends ClassLoader {
    
        private String rootDir;
    
        public MyClassLoader(String rootDir) {
            this.rootDir = rootDir;
        }
    
        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";
        }
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            System.out.println("自定义类加载器");
            byte[] classData = getClassData(name);
            if (classData == null) {
                throw new ClassNotFoundException();
            } else {
                return defineClass(name, classData, 0, classData.length);
            }
        }
    }
    
    编写需要加载的类
    package lorenzo;
    public class MyClass {
        @Override
        public String toString() {
            return "Hello Lorenzo!";
        }
    }
    
    编写测试类
    package lorenzo;
    public class Client {
        public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
            MyClassLoader myClassLoader = new MyClassLoader("/data");
            Class clazz = myClassLoader.loadClass("lorenzo.MyClass");
            System.out.println(clazz.newInstance().toString());
            System.out.println(myClassLoader.getClass().getClassLoader());
        }
    }
    

    注意:以上三个类都在/data/lorenzo文件夹下面
    mac控制台输入:

    cd /data/lorenzo
    javac MyClassLoader.java
    javac MyClass.java
    javac Client.java
    cd ..
    java ava lorenzo/Client

    output:

    Hello Lorenzo!
    sun.misc.Launcher$AppClassLoader@2a139a55

    分析结果:
    根据类加载器树形图可知

    类加载器树.png

    MyClassLoader.java和Client.java以及MyClass.java都在classpath目录下,他们由AppClassLoader类加载器加载。根据loadClass(String)的模版方法可知,MyClassLoader的父级类加载器AppClassLoader可以加载binary name 为lorenzo.MyClass的类,程序不会执行到loadClass的第三步,所以是AppClassLoader而不是MyClassLoader加载MyClass。

    修改代码

    把MyClass.class移动到data1/lorenzo的文件夹下
    修改Client中代码:

      MyClassLoader myClassLoader = new MyClassLoader("/data");
    

    修改后的代码为

    MyClassLoader myClassLoader = new MyClassLoader("/data1");
    

    mac控制台输入:

    cd /data/lorenzo
    javac Client.java
    cd ..
    java lorenzo/Client

    output:

    自定义类加载器
    Hello Lorenzo!
    sun.misc.Launcher$AppClassLoader@2a139a55

    注意确保/data/lorenzo目录没有MyClass.class。

    把自定义的类加载器挂载到ExtClassLoader
    1. 把MyClassLoader.class打成jar包

    cd /data
    jar cvf lorenzo.jar lorenzo/MyClassLoader.class

    1. 把lorenzo.jar复制到../jre/lib/ext/目录下

    java lorenzo/Client

    output:

    自定义类加载器
    Hello Lorenzo!
    sun.misc.Launcher$ExtClassLoader@75b84c92

    写在最后

    加密的类加载器思路,首先编译生成class文件,加密class文件,在自定义的类加载器解密。

    相关文章

      网友评论

          本文标题:自定义类加载器

          本文链接:https://www.haomeiwen.com/subject/sxjqbxtx.html