Javaクラスにおけるホットスワップの概念、設計と実現(2)
4269 ワード
カスタムClassLoaderの作成
クラスのロードプロセスを完全に管理するには、カスタムクラスローダをClassLoaderから直接継承する必要があります.まずClassLoaderクラスの中和熱置換に関するいくつかの重要な方法を紹介する.
◆findLoadedClass:各クラスローダには、同じ名前のクラスが2つも表示されないロード済みクラス名空間が維持されています.このクラスローダでロードされたクラスは、直接的でも間接的でも、自分の名前空間に保存されます.この方法は、その名前空間に指定されたクラスが存在するかどうかを探し、存在する場合はクラスへの参照に戻ります.そうしないとnullに戻ります.ここでの直接とは、そのクラスローダのロードパス上に存在し、そのローダによってロードが完了することを意味し、間接的には、そのクラスローダによってクラスのロード作業を他のクラスローダに委託してクラスの実際のロードを完了することを意味する.
◆getSystemClassLoader:Java 2に追加されたメソッド.このメソッドは、システムで使用されているClassLoaderを返します.この方法により,自分でカスタマイズしたクラスローダで一部の作業をシステムクラスローダに渡すことができる.
◆defineClass:クラスを変換すると同時に、クラスの親クラスと実装されたインタフェースクラスをロードするように要求されるクラスを受信し、クラスインスタンスに変換するClassLoaderにおいて非常に重要な方法です.
◆loadClass:クラスのエントリメソッドをロードし、このメソッドを呼び出してクラスの明示的なロードを完了します.この方法の再実装により、クラスのロードプロセスを完全に制御および管理できます.
◆resolveClass:指定したクラスをリンクします.これは、Java言語仕様の「実行」章の説明を参照して、クラスが使用可能であることを確認するために必要な方法です.
これらの方法については、カスタムクラス・ローダを実装して、クラス・ローダに直接ロードする必要があるクラスのセットを指定します.クラス・ローダがクラスのロードを行うときに、ロードするクラスがクラス・ローダによってロードされる必要があるセットに属している場合は、では、それによって直接クラスのロードを完了します.そうしないと、クラスのロードの仕事をシステムのクラスローダに依頼して完了します.
サンプルコードを与える前に、2つの点について説明する必要があります.1、同じクラスの異なるバージョンの共存を実現するには、これらの異なるバージョンは異なるクラスローダによってロードされなければならないので、これらのクラスのロード作業をシステムローダに依頼することはできません.これらのバージョンは1部しかないからです.2、これを行うために、システムのデフォルトのクラスローダ依頼ルールを採用することはできません.つまり、私たちがカスタマイズしたクラスローダの親ローダはnullに設定する必要があります.このカスタムクラス・ローダの実装コードは、次のとおりです.
このクラス・ローダの実装では、指定されたすべての直接ロードする必要があるクラスは、ローダがインスタンス化されたときにロードされ、loadClassによってクラスのロードが行われた場合、クラスがロードされておらず、そのクラス・ローダによってロードされなければならない列に属していない場合は、システム・ローダにロードが委任されます.
クラスのロードプロセスを完全に管理するには、カスタムクラスローダをClassLoaderから直接継承する必要があります.まずClassLoaderクラスの中和熱置換に関するいくつかの重要な方法を紹介する.
◆findLoadedClass:各クラスローダには、同じ名前のクラスが2つも表示されないロード済みクラス名空間が維持されています.このクラスローダでロードされたクラスは、直接的でも間接的でも、自分の名前空間に保存されます.この方法は、その名前空間に指定されたクラスが存在するかどうかを探し、存在する場合はクラスへの参照に戻ります.そうしないとnullに戻ります.ここでの直接とは、そのクラスローダのロードパス上に存在し、そのローダによってロードが完了することを意味し、間接的には、そのクラスローダによってクラスのロード作業を他のクラスローダに委託してクラスの実際のロードを完了することを意味する.
◆getSystemClassLoader:Java 2に追加されたメソッド.このメソッドは、システムで使用されているClassLoaderを返します.この方法により,自分でカスタマイズしたクラスローダで一部の作業をシステムクラスローダに渡すことができる.
◆defineClass:クラスを変換すると同時に、クラスの親クラスと実装されたインタフェースクラスをロードするように要求されるクラスを受信し、クラスインスタンスに変換するClassLoaderにおいて非常に重要な方法です.
◆loadClass:クラスのエントリメソッドをロードし、このメソッドを呼び出してクラスの明示的なロードを完了します.この方法の再実装により、クラスのロードプロセスを完全に制御および管理できます.
◆resolveClass:指定したクラスをリンクします.これは、Java言語仕様の「実行」章の説明を参照して、クラスが使用可能であることを確認するために必要な方法です.
これらの方法については、カスタムクラス・ローダを実装して、クラス・ローダに直接ロードする必要があるクラスのセットを指定します.クラス・ローダがクラスのロードを行うときに、ロードするクラスがクラス・ローダによってロードされる必要があるセットに属している場合は、では、それによって直接クラスのロードを完了します.そうしないと、クラスのロードの仕事をシステムのクラスローダに依頼して完了します.
サンプルコードを与える前に、2つの点について説明する必要があります.1、同じクラスの異なるバージョンの共存を実現するには、これらの異なるバージョンは異なるクラスローダによってロードされなければならないので、これらのクラスのロード作業をシステムローダに依頼することはできません.これらのバージョンは1部しかないからです.2、これを行うために、システムのデフォルトのクラスローダ依頼ルールを採用することはできません.つまり、私たちがカスタマイズしたクラスローダの親ローダはnullに設定する必要があります.このカスタムクラス・ローダの実装コードは、次のとおりです.
- class CustomCL extends ClassLoader {
-
- private String basedir; //
- private HashSet dynaclazns; //
-
- public CustomCL(String basedir, String[] clazns) {
- super(null); // null
- this.basedir = basedir;
- dynaclazns = new HashSet();
- loadClassByMe(clazns);
- }
-
- private void loadClassByMe(String[] clazns) {
- for (int i = 0; i < clazns.length; i++) {
- loadDirectly(clazns[i]);
- dynaclazns.add(clazns[i]);
- }
- }
-
- private Class loadDirectly(String name) {
- Class cls = null;
- StringBuffer sb = new StringBuffer(basedir);
- String classname = name.replace('.', File.separatorChar) + ".class";
- sb.append(File.separator + classname);
- File classF = new File(sb.toString());
- cls = instantiateClass(name,new FileInputStream(classF),
- classF.length());
- return cls;
- }
-
- private Class instantiateClass(String name,InputStream fin,long len){
- byte[] raw = new byte[(int) len];
- fin.read(raw);
- fin.close();
- return defineClass(name,raw,0,raw.length);
- }
-
- protected Class loadClass(String name, boolean resolve)
- throws ClassNotFoundException {
- Class cls = null;
- cls = findLoadedClass(name);
- if(!this.dynaclazns.contains(name) && cls == null)
- cls = getSystemClassLoader().loadClass(name);
- if (cls == null)
- throw new ClassNotFoundException(name);
- if (resolve)
- resolveClass(cls);
- return cls;
- }
-
- }
このクラス・ローダの実装では、指定されたすべての直接ロードする必要があるクラスは、ローダがインスタンス化されたときにロードされ、loadClassによってクラスのロードが行われた場合、クラスがロードされておらず、そのクラス・ローダによってロードされなければならない列に属していない場合は、システム・ローダにロードが委任されます.