类加载机制实现类的隐藏
前几天我写了一个类的加载机制,也就是有关类的加载顺序问题,这一次我们将了解一下如何利用自定义的类加载器实现类的隐藏,然后再运行的时候动态的读出被隐藏的类.这样就可以在一定的程度上保护我们的类了,我们还是先看看代码吧.
我们先写一个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);
}
}
* 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(){
}
}
* 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);
}
}
* 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的浓香.