类加载器

497 阅读1分钟

类加载器的作用:动态加载java class文件到jvm内存中,让jvm能够调用并执行class文件中的字节码

自定义类加载器

1、加载class文件的类加载器

1.1、类

在/Users/indi目录下有一个test.class文件

1.2、类加载器

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MyClassLoader extends ClassLoader {

    private String root;
    public String getRoot() {
        return root;
    }
    public void setRoot(String root) {
        this.root = root;
    }

    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classData = loadClassData(name);
        if (classData == null) {
            throw new ClassNotFoundException();
        } else {
            return defineClass(name, classData, 0, classData.length);
        }
    }

    private byte[] loadClassData(String className) {
        String fileName = root + File.separatorChar
                + className.replace('.', File.separatorChar) + ".class";
        try {
            InputStream ins = new FileInputStream(fileName);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int length = 0;
            while ((length = ins.read(buffer)) != -1) {
                baos.write(buffer, 0, length);
            }
            return baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

   
}

测试

public static void main(String[] args)  {
    MyClassLoader classLoader = new MyClassLoader();
    // root是类所在目录
    classLoader.setRoot("/Users/indi");

    Class<?> testClass = null;
    try {
        // test是类名称
        testClass = classLoader.loadClass("test");
        Object object = testClass.newInstance();
        System.out.println(object.getClass().getClassLoader());

        Method test = testClass.getMethod("test");
        test.invoke(object);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException | InvocationTargetException e) {
        e.printStackTrace();
    }
}

2、加载加密后的class文件的类加载器

2.1、对class文件进行加密

import java.io.*;

/**
 * 加密
 */
public class Encrypt {

    public static void main(String[] args) {
        encrypt(new File("/Users/indi/test.class"),new File("/Users/indi/encrypt/test.class"));
    }

    /**
     * 加密算法
     * @param rsource
     * @param target
     */
    public static void encrypt(File rsource,File target){
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream(rsource);
            fos = new FileOutputStream(target);
            int temp = -1;
            while ((temp = fis.read()) != -1){
                fos.write(temp ^ 0x98);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException ioException){

        }finally {
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

2.2、解密类加载器

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class DecryptClassLoader extends ClassLoader {

    private String root;

    public DecryptClassLoader(String root){
        this.root = root;
    }

    private static final String CLASS_SUFFIX = ".class";

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] data = this.loadClassData(name);
        if (data == null) {
            return super.findClass(name);
        }
        return super.defineClass(name, data, 0, data.length);
    }
    public byte[] loadClassData(String className) {
        String filePath = getFilePath(className);
        ByteArrayOutputStream bos = null;
        try {
            InputStream is = new FileInputStream(filePath);
            bos = new ByteArrayOutputStream();
            int temp = -1;
            while ((temp = is.read()) != -1) {
                bos.write(temp ^ 0x98);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            return bos.toByteArray();
        }
    }

    private String getFilePath(String className) {
        return this.root + File.separatorChar + className + CLASS_SUFFIX;
    }
}

测试

public static void main(String[] args) {
    DecryptClassLoader classLoader = new DecryptClassLoader("/Users/indi/encrypt");
    try {
        Class<?> clazz = classLoader.findClass("test");
        Object obj = clazz.newInstance();
        Method method = clazz.getMethod("test");
        method.invoke(obj);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
        e.printStackTrace();
    }
}