classloaderについて
詳細
jvmが持参した3つのclassloader
1.Bootstrap classloaderは、jvmの一部であり、Cによって書かれ、コアライブラリが呼び出されます.
sun javaでは、呼び出しクラスパスを次の文で表示できます.
と書く
%JAVA_HOME%/jre/lib/resources.jar
%JAVA_HOME%/jre/lib/rt.jar
%JAVA_HOME%/jre/lib/sunrsasign.jar
%JAVA_HOME%/jre/lib/jsse.jar
%JAVA_HOME%/jre/lib/jce.jar
%JAVA_HOME%/jre/lib/charsets.jar
%JAVA_HOME%/jre/lib/jfr.jar
%JAVA_HOME%/jre/classes
2.ExtClassLoader、システム拡張クラスを呼び出す
と書く
%JAVA_HOME%/jre/lib/ext/access-bridge.jar
%JAVA_HOME%/jre/lib/ext/cldrdata.jar
%JAVA_HOME%/jre/lib/ext/dnsns.jar
%JAVA_HOME%/jre/lib/ext/jaccess.jar
%JAVA_HOME%/jre/lib/ext/jfxrt.jar
%JAVA_HOME%/jre/lib/ext/localedata.jar
%JAVA_HOME%/jre/lib/ext/nashorn.jar
%JAVA_HOME%/jre/lib/ext/sunec.jar
%JAVA_HOME%/jre/lib/ext/sunjce_provider.jar
%JAVA_HOME%/jre/lib/ext/sunmscapi.jar
%JAVA_HOME%/jre/lib/ext/sunpkcs11.jar
%JAVA_HOME%/jre/lib/ext/zipfs.jar
3.AppClassLoader、classpathのクラスを呼び出す
この3つのクラスは、親委任モデルに従います.つまり、クラスをロードするたびに、親マウントからロードされます.レベルが見つからないと、クラスが1つ下に移動します.これはclasspathのクラスがjdkに付属しているクラスを上書きできない理由です.
tomcatなどのアプリケーションでは、webapp分離にかかわるため、各webappのクラスをロードする際に親委任モデルに従わず、自分が呼び出したクラスを優先するキーがあります.また、ここには暗黙的なマウント、すなわちキーワードnewでオブジェクトを作成する際に、このクラスをロードするために使用されるマウントがnewキーワードを使用するクラスのマウントであるというキーがあります.
次のコードは、このプロセスをシミュレートします.
カスタムクラスマウンタ
テスト
次のクラスは上のコードのclasspathに入れないでください.
jvmが持参した3つのclassloader
1.Bootstrap classloaderは、jvmの一部であり、Cによって書かれ、コアライブラリが呼び出されます.
sun javaでは、呼び出しクラスパスを次の文で表示できます.
URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
と書く
%JAVA_HOME%/jre/lib/resources.jar
%JAVA_HOME%/jre/lib/rt.jar
%JAVA_HOME%/jre/lib/sunrsasign.jar
%JAVA_HOME%/jre/lib/jsse.jar
%JAVA_HOME%/jre/lib/jce.jar
%JAVA_HOME%/jre/lib/charsets.jar
%JAVA_HOME%/jre/lib/jfr.jar
%JAVA_HOME%/jre/classes
2.ExtClassLoader、システム拡張クラスを呼び出す
と書く
%JAVA_HOME%/jre/lib/ext/access-bridge.jar
%JAVA_HOME%/jre/lib/ext/cldrdata.jar
%JAVA_HOME%/jre/lib/ext/dnsns.jar
%JAVA_HOME%/jre/lib/ext/jaccess.jar
%JAVA_HOME%/jre/lib/ext/jfxrt.jar
%JAVA_HOME%/jre/lib/ext/localedata.jar
%JAVA_HOME%/jre/lib/ext/nashorn.jar
%JAVA_HOME%/jre/lib/ext/sunec.jar
%JAVA_HOME%/jre/lib/ext/sunjce_provider.jar
%JAVA_HOME%/jre/lib/ext/sunmscapi.jar
%JAVA_HOME%/jre/lib/ext/sunpkcs11.jar
%JAVA_HOME%/jre/lib/ext/zipfs.jar
3.AppClassLoader、classpathのクラスを呼び出す
この3つのクラスは、親委任モデルに従います.つまり、クラスをロードするたびに、親マウントからロードされます.レベルが見つからないと、クラスが1つ下に移動します.これはclasspathのクラスがjdkに付属しているクラスを上書きできない理由です.
tomcatなどのアプリケーションでは、webapp分離にかかわるため、各webappのクラスをロードする際に親委任モデルに従わず、自分が呼び出したクラスを優先するキーがあります.また、ここには暗黙的なマウント、すなわちキーワードnewでオブジェクトを作成する際に、このクラスをロードするために使用されるマウントがnewキーワードを使用するクラスのマウントであるというキーがあります.
次のコードは、このプロセスをシミュレートします.
カスタムクラスマウンタ
package jp.co.wqf;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class MyClassLoader extends ClassLoader {
private String name;
private String path = "D:/";
private final String fileType = ".class";
public MyClassLoader(String name){
super();
this.name = name;
}
public MyClassLoader(String name, ClassLoader cl){
super(cl);
this.name = name;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
@Override
protected Class> findClass(String name) throws ClassNotFoundException {
byte[] data = loaderClassData(name);
return this.defineClass(name, data, 0, data.length);
}
private byte[] loaderClassData(String className){
InputStream is = null;
byte[] data = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
String fileName = className.replace(".", "/");
try {
is = new FileInputStream(new File(path + fileName + fileType));
int c = 0;
while(-1 != (c = is.read())){
baos.write(c);
}
data = baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally{
try {
is.close();
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return data;
}
}
テスト
package jp.co.wqf;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyClassLoader classLoader = new MyClassLoader("classload1");
classLoader.setPath("/eclipse/workspace/Test/bin/");
try {
Class> clsA = classLoader.loadClass("jp.co.wqf.A");
Object objA = clsA.newInstance();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
次のクラスは上のコードのclasspathに入れないでください.
package jp.co.wqf;
public class A {
private B b;
public A(){
this.b = new B();
}
}
package jp.co.wqf;
public class B {
private C c;
public B(){
this.c = new C();
}
}
package jp.co.wqf;
public class C {
public C(){
System.out.println("create class c!");
}
}