/**
* 类加载器
* java类通过类加载器将类加载到虚拟机中,那么加载器又是谁来加载它呢?
* 显然,根类加载器不是java类,是BootStrap 它嵌入在JVM的内核中
* 他还有两个子的类加载器:ExtClassLoader和AppClassLoader
* @author shantui *
*/
//类加载器的包含关系:
/*
* null(BootStrap)>ExtClassLoader>AppClassLoader
* AppClassLoader管辖范围:CLASSPATH指定的所有jar或目录 ,systemclassloader
* ExtClassLoader管辖范围:JRE lib ext / *.jar
* BootStrap 管辖范围:JRE lib rt.jar
*
* 自定义加载器,必须用我提供的加载器才能加载我放在指定目录下
* 的类,实现加密功能。
* 调用ClassLoader.Loadclass()来指定类加载器去加载某类。
* 如果指定加载器去找某类,它不会直接找,而是直接溯源(委托机制)到BootStrap让
* 它去找,如果他也没找到就推回来给子类找,再找不到再给子子类也就是最先
* 发起溯源的那个类,只要又返回了发起者手里,还找不到就报异常,这样避免了字节码会多次加载的问题
/**
* 模版方法设计模式
* 父类里面有个方法f,f里面有个细节流程定义为抽象方法F
* 留待子类去完成
* 子类1里面有自己独特的f1,子类2里面有独特f2 *
*/
自定义加载器演示:
要实现的功能:定义一个加密方法,读取包里的一个类文件的同时把从类文件读到的每个字节
与或0xff,把这个类文件字节打乱,把加密好的类文件存放到指定的目录下面。
自定义一个解密用的类加载器,限制虚拟机对默认类加载器的使用,而调用自定义的加载器,在加载被加密类的过程中,实现对类的解密。
思路:定义一个加载器类,用来 实现读取类文件并加密,并实现对加密后的类进行加载并解密处理。
定义一个被加密的类,用于演示加密和不加密的区别,只重写其toString方法,打印演示
定义一个解密类,运行此类可以调用解密方法。
加载器类代码:
1: package jiami;
2:
3: public class ClassLoaderTest
4: {
5: public static void main(String[] args) throws Exception
6: {
7: //看一下我们新建的这个类是谁加载的
8: //System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());
9:
10: ClassLoader loader = ClassLoaderTest.class.getClassLoader();
11: //看一下我们新建的这个类的父亲都是谁(null就是那个内核根加载器)
12: while(loader!=null)
13: {
14: System.out.println(loader.getClass().getName());
15: loader =loader.getParent();
16: }
17: System.out.println(loader);
18: }
19: }
定义一个被加密的类,用于演示加密和不加密的区别
1: package jiami;
2:
3: public class JiaMiDiaoYong {
4:
5: /**
6: * @param args
7: */
8: public static void main(String[] args) {
9: // TODO Auto-generated method stub
10: //调用一下加密过的类ClassLoaderAttachment,发现已经无法编译了 。加密成功
11: //new ClassLoaderAttachment().toString();
12:
13: }
14:
15: }
定义自定义加载器类,在main方法里实现以下功能:
把要加密的类加密后存入指定文件夹中;
利用自定义的加载器去加装加密后的类,并解密,生成一个新的类文件
代码如下:
1: package jiami;
2: import java.io.ByteArrayOutputStream;
3: import java.io.FileInputStream;
4: import java.io.FileNotFoundException;
5: import java.io.FileOutputStream;
6: import java.io.InputStream;
7: import java.io.OutputStream;
8:
9: public class myClassLoader extends ClassLoader
10: {
11: public myClassLoader(){}
12: public myClassLoader(String classDir)
13: {
14: this.classDir=classDir;
15: }
16: public static void main(String[] args) throws Exception
17: {
18:
19: //源 地址通过eclipse软件人为设定为args[0]
20: String srcPath = args[0];//传来的第一个值就是源路径
21: String destDir = args[1];//传来的第二个就是目的路径
22: //定义文件读取流 对象,关联要被加密的类文件地址。
23: FileInputStream fis =new FileInputStream(srcPath);
24: //定义生产的加密文件的名字,还是和原来的文件名一样,通过截取源路径最后的文件名形式
25: String destFileName=srcPath.substring(srcPath.lastIndexOf('\\')+1);
26: //定义被加密后文件要存放的路径:文件夹/类文件名
27: String destPath=destDir+"\\"+destFileName;
28: //定义文件读取流对象,关联到要输出的路径
29: FileOutputStream fos = new FileOutputStream (destPath);
30: //把读取到的类文件输入流加密后,返回已写入了加密内容的类文件的输出流
31: cypher(fis,fos);
32: //关闭两个流对象
33: fis.close();
34: fos.close();
35: }
36: //加密函数
37: private static void cypher(InputStream ips ,OutputStream ops)throws Exception
38: {
39: int b =-1;
40: while ((b=ips.read())!=-1)
41: {
42: ops.write(b ^ 0xff);
43: }
44: }
45:
46:
47: private String classDir;
48: //自定义一个类加载器
49: @Override//覆盖其findClass方法,不让其传递给父类,自己找
50: protected Class<?> findClass(String name) throws ClassNotFoundException {
51: // TODO Auto-generated method stub
52: //拼出要加载的已加密并放在另一个文件夹中的类文件的路径
53: String classFileName=classDir+"\\"+name+".class";
54: //读取系统上的文件要进行异常处理
55: try {
56: //定义读取流对象关联要解密的类文件
57: FileInputStream fis =new FileInputStream(classFileName);
58: //定义一个字节数组输出流,用以缓存解密后的字节文件 ,数据缓冲专用流,数组不可以用以做缓冲区
59: ByteArrayOutputStream bos=new ByteArrayOutputStream();
60: //加密和解密一个函数
61: cypher(fis,bos);
62: //关流
63: fis.close();
64: //把缓冲区里的字节存入字节数组中
65: byte[] bytes=bos.toByteArray();
66: //利用defineClass方法,把字节数组 转换为类文件
67: return defineClass(null,bytes,0,bytes.length);
68:
69:
70: }
71: catch (Exception e) {
72: // TODO Auto-generated catch block
73: e.printStackTrace();
74: }
75: return super.findClass(name);//若子类搞不定,否就返回父类的,让父类去找
76:
77: }
78: }
定义一个加密器,运行即可对指定类文件加密
1: package jiami;
2:
3: public class JiaMiDiaoYong {
4:
5: /**
6: * @param args
7: */
8: public static void main(String[] args) {
9: // TODO Auto-generated method stub
10: //调用一下加密过的类ClassLoaderAttachment,发现已经无法编译了 。加密成功
11: //new ClassLoaderAttachment().toString();
12:
13: }
14:
15: }
定义一个解密器,运行即可对加密过的文件解密
1: package jiami;
2:
3: import java.util.Date;
4:
5: public class JieMiDiaoYong {
6:
7: /**
8: * @param args *
9: */
10: public static void main(String[] args) throws Exception {
11: // TODO Auto-generated method stub
12: Class clazz= new myClassLoader("ItClassLib").loadClass("ClassLoaderAttachment");
13: //此时返回值的类型不能写ClassLoaderAttachment,因为它已经被加密搞烂了,所以
14: //返回值类型只能用它的父类来装一下
15: Object d1=(Object)clazz.newInstance();
16: System.out.println(d1);
17: }
18:
19: }