自定义的类加载器必须继承ClassLoader抽象类,并覆盖findClass方法。
测试的需要被加密使用的类:
package com.franky.classloader;
import java.util.Date;
/**
* @描述 加密的测试类,需要用自定义的类加载器加载
* @作者 franky
* @日期 2015-1-1 下午9:51:38
*
*/
public class TestMyClass extends Date {
@Override
public String toString() {
return "hello,world";
}
}
自定义的类加载器,能够对类进行加密解密:
package com.franky.classloader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* @描述 自定义的类加载器,提供对类的加载,加密与加密
* @作者 franky
* @日期 2015-1-1 下午9:47:14
*
*/
public class MyClassLoader extends ClassLoader{
/**
* 进行class文件的加密
* @param args 传入的源文件路径,和加密后的文件夹存储路径
* @throws IOException 抛出的IO异常
*/
public static void main(String[] args) throws IOException {
FileInputStream ips = new FileInputStream(args[0]);
String destFile = args[0].substring(args[0].lastIndexOf("\\")+1);
// System.out.println(destFile);
// System.out.println(args[1]);
if(!(new File(args[1])).exists()){
new File(args[1]).mkdir();
}
String destPath = args[1]+"\\"+destFile;
FileOutputStream ops = new FileOutputStream(destPath);
encrypt(ips,ops);
ips.close();
ops.close();
}
/**
* 类的加密器与解密器
* @param ips 需要加密的class文件读取流
* @param ops 加密完成的class文件输出流
* @throws IOException 抛出的IO异常
*/
private static void encrypt(InputStream ips, OutputStream ops) throws IOException {
int b = -1;
while((b = ips.read())!=-1){
ops.write(b^0xff);
}
}
private String classDir;
public MyClassLoader() {
}
/**类加载器的有参构造方法
* @param classDir 存放加密类的目录
*/
public MyClassLoader(String classDir) {
this.classDir = classDir;
}
@Override
/* 覆盖findClass方法后,才能实现自定义加载类
* 该方法负责从加密的class目录中,加载自定义的加密类,解密后返回该类的Class对象
*/
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = name.substring(name.lastIndexOf(".")+1)+".class";
String destPath = this.classDir +"\\"+className;
try {
FileInputStream fis = new FileInputStream(destPath);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
encrypt(fis,bos);
byte[] bs = bos.toByteArray();
Class<?> defineClass = defineClass(null,bs, 0, bs.length);
return defineClass;
} catch (Exception e) {
e.printStackTrace();
}
return super.findClass(name);
}
}
测试自定义类加载器的测试主类:
package com.franky.classloader;
import java.util.Date;
/**
* @描述 测试自定义的类加载器
* @作者 franky
* @日期 2015-1-1 下午10:11:05
*
*/
public class MyClassLoaderTest {
public static void main(String[] args) throws Exception {
//经过加密的类加载器对TestMyclass.class文件加载,该实例对象的.class文件是无法正常加载的
//System.out.println(new TestMyClass());
//用自定义的类加载器对TestMyclass.class进行加载,按照原始路径加载,classpath下找不到,
//然后返回自定义的类加载器,执行findClass方法,找到对应的加密类.class文件进行加载
Class<?> clazz = new MyClassLoader("mylib").loadClass("com.franky.classloader.TestMyClass");
//不能直接转换为被加密的类,因为字节码已经被加密了,所以只能向上转型加载它的父类型
Date obj = (Date) clazz.newInstance();
//能够正确输出
System.out.println(obj);
}
}