Javaクラスにおけるホットスワップの概念、設計と実現(2)

4269 ワード

カスタムClassLoaderの作成
クラスのロードプロセスを完全に管理するには、カスタムクラスローダをClassLoaderから直接継承する必要があります.まずClassLoaderクラスの中和熱置換に関するいくつかの重要な方法を紹介する.
◆findLoadedClass:各クラスローダには、同じ名前のクラスが2つも表示されないロード済みクラス名空間が維持されています.このクラスローダでロードされたクラスは、直接的でも間接的でも、自分の名前空間に保存されます.この方法は、その名前空間に指定されたクラスが存在するかどうかを探し、存在する場合はクラスへの参照に戻ります.そうしないとnullに戻ります.ここでの直接とは、そのクラスローダのロードパス上に存在し、そのローダによってロードが完了することを意味し、間接的には、そのクラスローダによってクラスのロード作業を他のクラスローダに委託してクラスの実際のロードを完了することを意味する.
◆getSystemClassLoader:Java 2に追加されたメソッド.このメソッドは、システムで使用されているClassLoaderを返します.この方法により,自分でカスタマイズしたクラスローダで一部の作業をシステムクラスローダに渡すことができる.
◆defineClass:クラスを変換すると同時に、クラスの親クラスと実装されたインタフェースクラスをロードするように要求されるクラスを受信し、クラスインスタンスに変換するClassLoaderにおいて非常に重要な方法です.
◆loadClass:クラスのエントリメソッドをロードし、このメソッドを呼び出してクラスの明示的なロードを完了します.この方法の再実装により、クラスのロードプロセスを完全に制御および管理できます.
◆resolveClass:指定したクラスをリンクします.これは、Java言語仕様の「実行」章の説明を参照して、クラスが使用可能であることを確認するために必要な方法です.
これらの方法については、カスタムクラス・ローダを実装して、クラス・ローダに直接ロードする必要があるクラスのセットを指定します.クラス・ローダがクラスのロードを行うときに、ロードするクラスがクラス・ローダによってロードされる必要があるセットに属している場合は、では、それによって直接クラスのロードを完了します.そうしないと、クラスのロードの仕事をシステムのクラスローダに依頼して完了します.
サンプルコードを与える前に、2つの点について説明する必要があります.1、同じクラスの異なるバージョンの共存を実現するには、これらの異なるバージョンは異なるクラスローダによってロードされなければならないので、これらのクラスのロード作業をシステムローダに依頼することはできません.これらのバージョンは1部しかないからです.2、これを行うために、システムのデフォルトのクラスローダ依頼ルールを採用することはできません.つまり、私たちがカスタマイズしたクラスローダの親ローダはnullに設定する必要があります.このカスタムクラス・ローダの実装コードは、次のとおりです.

  
    
  1. class CustomCL extends ClassLoader {  
  2.  
  3. private String basedir; //  
  4.     private HashSet dynaclazns; //  
  5.  
  6.     public CustomCL(String basedir, String[] clazns) {  
  7.         super(null); // null  
  8.         this.basedir = basedir;  
  9.         dynaclazns = new HashSet();  
  10.         loadClassByMe(clazns);  
  11.     }  
  12.  
  13.     private void loadClassByMe(String[] clazns) {  
  14.         for (int i = 0; i < clazns.length; i++) {  
  15.             loadDirectly(clazns[i]);  
  16.             dynaclazns.add(clazns[i]);  
  17.         }  
  18.     }  
  19.  
  20.     private Class loadDirectly(String name) {  
  21.         Class cls = null;  
  22.         StringBuffer sb = new StringBuffer(basedir);  
  23.         String classname = name.replace('.', File.separatorChar) + ".class"; 
  24.         sb.append(File.separator + classname);  
  25.         File classF = new File(sb.toString());  
  26.         cls = instantiateClass(name,new FileInputStream(classF), 
  27.             classF.length());  
  28.         return cls;  
  29.     }      
  30.  
  31.     private Class instantiateClass(String name,InputStream fin,long len){  
  32.         byte[] raw = new byte[(int) len];  
  33.         fin.read(raw);  
  34.         fin.close();  
  35.         return defineClass(name,raw,0,raw.length);  
  36.     }  
  37.      
  38. protected Class loadClass(String name, boolean resolve)  
  39.             throws ClassNotFoundException {  
  40.         Class cls = null;  
  41.         cls = findLoadedClass(name);  
  42.         if(!this.dynaclazns.contains(name) && cls == null)  
  43.             cls = getSystemClassLoader().loadClass(name);  
  44.         if (cls == null)  
  45.             throw new ClassNotFoundException(name);  
  46.         if (resolve)  
  47.             resolveClass(cls);  
  48.         return cls;  
  49.     }  
  50.  

このクラス・ローダの実装では、指定されたすべての直接ロードする必要があるクラスは、ローダがインスタンス化されたときにロードされ、loadClassによってクラスのロードが行われた場合、クラスがロードされておらず、そのクラス・ローダによってロードされなければならない列に属していない場合は、システム・ローダにロードが委任されます.