自分のclassloaderを作成して暗号化されたclassをロードします

4287 ワード

1 Dateクラスを継承するクラスを作成します.
package erica.classloader;
import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Date;
public class ClassLoaderAttachment extends Date {
 @Override  public String toString() {        return "hello erica";   } 
}
 
 
2ロードしたclassファイルを作成し、生成したclassファイルをD:itunesに置くことができるクラスを作成します.
package erica.classloader;
import java.io.*;
public class MyClassLoader {
 
 public static  void cypher(InputStream in,OutputStream out) throws IOException{       int b=-1;       while((b=in.read())!=-1){        out.write(b^0xff);   }     }  
}
3暗号化生成後のclassの実行
public static void main(String[] args) throws Exception {       String srcPath="D:/workspace/WorkSpaceSpring/ReflectTest/bin/erica/classloader/ClassLoaderAttachment.class";       String descPath="D:\\itunes\\ClassLoaderAttachment.class";       FileInputStream fis=new  FileInputStream(srcPath);       FileOutputStream fos=new  FileOutputStream(descPath);       cypher(fis,fos);       System.out.println("success");  }
 
 
 
4生成したclassを元のクラスのclassファイルに上書きし、java仮想マシン特定のclassloaderでファイルをロードするとエラーが発生します.
package erica.classloader;
import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Date;
public class ClassLoaderAttachment extends Date {
 @Override  public String toString() {        return "hello erica";  }       public static void main(String[] args) throws Exception {
  ClassLoaderAttachment  ca=new ClassLoaderAttachment();    System.out.println(ca);  }   }
エラーは図のように表示されます.
5それでは、暗号化されたclassをロードするために、私たち自身の書いたクラスローダです.
1:ClassLoaderクラスの継承
2:protected Classを上書きfindClass(String name)throws ClassNotFoundExceptionメソッド
3:defineClassを呼び出し、byte配列をClassクラスのインスタンスに変換します.このインスタンスは、バイナリバイトコードの列をロードしたClassのオブジェクトです.
public class MyClassLoader extends ClassLoader{
 
private String dir;    public MyClassLoader(){     }        public MyClassLoader(String dir){         this.dir=dir;  }
 
 @Override   protected  ClassfindClass(String name)throws ClassNotFoundException{          System.out.println("findClass");          String classname=dir+"/"+name+".class";          FileInputStream fis;   try {           fis = new  FileInputStream(classname);          ByteArrayOutputStream out=new ByteArrayOutputStream();          cypher(fis,out);           fis.close();          byte[]bytes=out.toByteArray();          return defineClass(null,bytes,0,bytes.length);   } catch (Exception e) {        e.printStackTrace();   }          return null;   }
 
}
 
 
6:自分のクラスローダで自分のバイトコードをロードする
public static void main(String[] args) throws Exception {           MyClassLoader  loader=new MyClassLoader("erica");        Date d=(Date)loader.loadClass("ClassLoaderAttachment").newInstance();        //Date d=(Date)loader.loadClass("erica.classloader.ClassLoaderAttachment").newInstance();//パッケージ名+クラス名Systemが指定されているため、元のclassがロードされます.out.println(d);      }  
印刷結果:
findClass hello erica
findClass文字列が印刷され、独自のクラスローダが実行されていることを示します.
 
 
jdkドキュメントの自己作成クラスローダの例を次に示します.
たとえば、アプリケーションは、サーバからクラスファイルをダウンロードするネットワーククラスローダを作成できます.サンプルコードは次のとおりです.
   ClassLoader loader = new NetworkClassLoader(host, port);
   Object main = loader.loadClass("Main", true).newInstance();
          . . .
 

ネットワーククラスローダサブクラスは、ネットワークからクラスをロードする方法findClassおよびloadClassDataを定義する必要があります.クラスを構成するバイトをダウンロードした後、メソッドdefineClassを使用してクラスインスタンスを作成する必要があります.例は次のようになります.
     class NetworkClassLoader extends ClassLoader {
         String host;
         int port;

         public Class findClass(String name) {
             byte[] b = loadClassData(name);
             return defineClass(name, b, 0, b.length);
         }

         private byte[] loadClassData(String name) {
             // load the class data from the connection
              . . .
         }
     }