- 为什么要自定义一个类的加载器呢,其实主要是由于,Java代码可以轻易的被反编译,如果你需要把自己的代码进行加密以防止反编译,可以先将编译后的代码用某种加密算法加密,类加密后就不能再用Java的ClassLoader去加载类了,这时就需要自定义ClassLoader在加载类的时候先解密类,然后再加载。
- 简单说一下有几种类的加载器,在jdk中有三种类的加载器,
①引导类的加载器(BootStrap):加载“JAVA_HOME/jre/lib//rt.jar”这个jar包里面的类,比如Date String 等;
②扩展类的加载器(exe):加载 “JAVA_HOME/jre/lib/exe/*.jar”这个路径下的所有jar包中的类的;
③应用类加载器(app):加载类路径下的所有class。 接下来是一些代码来演示将一个类加密再用自己定义的类的加载器进行解密并运行的过程
①. 首先定义一个类我们用Man来做
package com.classloader;
public class Man {
public static void run(){
System.out.println("走你>>>>>>>....");
}
}
②. 定义一个类用,在其中定义静态static方法,用来将以上代码(即刚写的Man类)所生成的.class文件进行加密,和解密
package com.classloader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class Encrypt {
//简单的输入输出操作
public static void coding(File src,File dest) throws Exception{
InputStream is = new FileInputStream(src);
OutputStream os = new FileOutputStream(dest);
int data;
while((data=is.read())!=-1){
data = encryptAndDecrypt(data);
os.write(data);
}
//原来的.class文件删除
src.delete();
is.close();
os.close();
}
//将计算机在.class文件中读到的每一个字节进行加密操作,当然了解密也是用这个方法,因为A^n^n==A
public static int encryptAndDecrypt(int data){
return data^("这是密码".hashCode());
}
}
③. 编写自己。自定义的类的加载器,需要继承ClassLoader类,并重写findClas方法
package com.classloader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class MyClassLoader extends ClassLoader {
// 加载类的路径
private String path;
public MyClassLoader(String path) {
super();
this.path = path;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
//其实这个name是类的全路径名
try {
//获得class的名称
name = name.substring(name.lastIndexOf(".")+1);
//这里其实是编辑新的文件的文件名称,因为我将会把电脑生成的class文件,用io的方式重新,写到自定义类的加载器要加载的路径下面,这里的path就是该路径,其中所有的文件名称都将会是,[类的名称+".amm"]的形式(.amm,是我的博客名称缩写,这里作为文件后缀了)
File file = new File(path + name + ".amm");
//将class文件写入内存
InputStream is = new FileInputStream(file);
ByteArrayOutputStream bo = new ByteArrayOutputStream();
int len;
while ((len = is.read()) != -1) {
//重新进行解码
bo.write(Encrypt.encryptAndDecrypt(len));
}
is.close();
byte[] byteArray = bo.toByteArray();
//找到类
Class<?> defineClass = defineClass(null,byteArray, 0, byteArray.length);
return defineClass;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return super.findClass(name);
}
}
④. 编写测试类进行,对自定义的类的加载器进行测试
package com.classloader;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws Exception {
//对正常的类进行加密操作
//这里是计算机自己产生的正常的lass路径
File src = new File("D:\\develop\\eclipse-jee-mars-2-win32\\servlet\\ClassLoader\\bin\\com\\classloader\\Man.class");
File dest = new File("class_loader_test/Man.lhy");
Encrypt.coding(src, dest);
ClassLoader myClassLoader = new MyClassLoader("class_loader_test/");
Class<?> loadClass = myClassLoader.loadClass("com.classloader.Man");
ClassLoader loader = loadClass.getClassLoader();
System.out.println("==="+loader); //打印加载器的名称,如果是自定义加载器架加载的该文件,则会出现该加载器的名称(这里是我运行出来的结果===com.classloader.MyClassLoader@888e6c)
Method method = loadClass.getMethod("run", null);
method.invoke(loadClass.newInstance(),null);
}
}
④.运行结果
以上则是我的理解。希望我们都在变成大牛的路上一去不复返,我爱你ლ(′◉❥◉`ლ)