类加载机制实现类的隐藏

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

我们先写一个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的浓香.

你可能感兴趣的:(类加载机制实现类的隐藏)