千里冰封
JAVA 浓香四溢
posts - 151,comments - 2801,trackbacks - 0
前几天我写了一个类的加载机制,也就是有关类的加载顺序问题,这一次我们将了解一下如何利用自定义的类加载器实现类的隐藏,然后再运行的时候动态的读出被隐藏的类.这样就可以在一定的程度上保护我们的类了,我们还是先看看代码吧.

我们先写一个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 千里冰封 阅读(955) 评论(3)  编辑  收藏 所属分类: JAVASE

FeedBack:
# re: 类加载机制实现类的隐藏
2007-09-24 12:39 | 狂放不羁
不错。哈哈。偶也在学习这个。  回复  更多评论
  
# re: 类加载机制实现类的隐藏
2007-09-24 12:54 | 千里冰封
你也来blogjava?  回复  更多评论
  
# re: 类加载机制实现类的隐藏
2007-09-26 16:40 | 狂放不羁
对。blogjava里面有很多高手写的东西。看看挺不错的哈哈。  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: