前几天我写了一个类的加载机制,也就是有关类的加载顺序问题,这一次我们将了解一下如何利用自定义的类加载器实现类的隐藏,然后再运行的时候动态的读出被隐藏的类.这样就可以在一定的程度上保护我们的类了,我们还是先看看代码吧.
我们先写一个URLClassLoader的子类,这样我们就可以用定义在其中的一些protected方法了.
/*
* Test6.java
*
* Created on 2007-9-24, 10:57:57
*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package test1;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author hadeslee
*/
@SuppressWarnings(value = "unchecked")
public class Test6 extends URLClassLoader {
public Test6() {
super(new URL[0]);
Thread.currentThread().setContextClassLoader(this);
ClassLoader cl = this.getClass().getClassLoader();
if (cl instanceof URLClassLoader) {
URLClassLoader loader = (URLClassLoader) cl;
URL[] urls = loader.getURLs();
for (URL u : urls) {
System.out.println(u);
this.addURL(u);
}
}
}
//根据类的全限定名得到类的字节数组
private byte[] getClassData(String name) {
try {
InputStream is = this.getClass().getResourceAsStream(getPathName(name));
byte[] temp = new byte[is.available()];
is.read(temp);
is.close();
return temp;
} catch (IOException ex) {
Logger.getLogger(Test6.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
//要隐藏的类
private void hideClasses(String className) {
DataOutputStream dout = null;
try {
dout = new DataOutputStream(new FileOutputStream("hide.dat"));
for (String s : className) {
dout.writeUTF(s);
byte[] data = this.getClassData(s);
dout.writeInt(data.length);
dout.write(data);
}
} catch (IOException ex) {
Logger.getLogger(Test6.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
dout.close();
} catch (IOException ex) {
Logger.getLogger(Test6.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
private Class findClass0(String className){
DataInputStream din = null;
try {
din = new DataInputStream(new FileInputStream("hide.dat"));
while (true) {
String name = din.readUTF();
System.out.println("find name=" + name);
int length = din.readInt();
byte[] data = new byte[length];
din.read(data);
if (name.equals(className)) {
return this.defineClass(name, data, 0, length);
}
}
} catch (IOException ex) {
Logger.getLogger(Test6.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassFormatError classFormatError) {
} finally {
try {
if (din != null) {
din.close();
}
} catch (Exception exe) {
exe.printStackTrace();
}
}
return null;
}
protected Class findClass(String className) throws ClassNotFoundException {
Class c=this.findClass0(className);
if(c==null){
return super.findClass(className);
}else{
return c;
}
}
//根据类名得到完整的加载路径名
private String getPathName(String name) {
StringBuilder sb = new StringBuilder();
String[] names = name.split("\\.");
for (String s : names) {
sb.append("/").append(s);
}
sb.append(".class");
return sb.toString();
}
public static void main(String[] args) throws Exception {
Test6 t = new Test6();
t.hideClasses("test2.A", "test2.B");
Class c = t.findClass("test2.B");
Object o = c.newInstance();
test2.B b=(test2.B)o;
Method m = c.getDeclaredMethod("print", String.class);
m.invoke(o, "我是中国人");
System.out.println(c);
}
}
以下是A和B类的代码
/*
* A.java
*
* Created on 2007-9-24, 10:26:47
*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package test2;
/**
*
* @author hadeslee
*/
public class A {
private int index=10;
public void doSth(){
}
}
/*
* B.java
*
* Created on 2007-9-24, 10:29:04
*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package test2;
/**
*
* @author hadeslee
*/
public class B extends A{
public void print(String s){
System.out.println(s);
}
}
此程序的实现思路是:先写一个继承自URLClassLoader的类加载器,然后我们要类的时候,就从这个类加载器去加载,我们要隐藏类的时候,也是由这个类加载器去实现隐藏, 其实隐藏就是把很多类放到一个文件里面去,然后加上自己的IO写法,然后在需要的时候,又可以又自己写进去的方法,把类的字节数组读出来,把它还原成一个类.在这里我们还需要重写一个方法,那就是定义在ClassLoader里面的findClass(String name)的方法,让它在找类的时候,不要乱找,而是用我们自己的方法来找,当我们自己的方法找不到的时候,才由它来找,这样的话,就可以实现先找我们自己的方式隐藏的类,再找一般情况下面的类.
对于类的加载,有很多东西是可以研究和学习的,希望在以后的学习过程中,能够慢慢了解它.
尽管千里冰封
依然拥有晴空
你我共同品味JAVA的浓香.
posted on 2007-09-24 11:04
千里冰封 阅读(962)
评论(3) 编辑 收藏 所属分类:
JAVASE