クラスローダメモその2
クラスローダを自作する場合
1. DirectoryClassLoader の作成
import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class DirectoryClassLoader extends ClassLoader { private static final int BUFFER_SIZE = 1024; private final String targetDirectory; DirectoryClassLoader(String targetDirectory) { if (targetDirectory == null) { throw new IllegalArgumentException( "TargetDirectory should not be null."); } if (targetDirectory.equals("")) { throw new IllegalArgumentException( "TargetDirectory should not be blank."); } this.targetDirectory = targetDirectory; } protected Class findClass(String name) throws ClassNotFoundException { try { byte[] data = read(new File(targetDirectory, name + ".class")); return defineClass(name, data, 0, data.length); } catch (Throwable t) { throw new ClassNotFoundException(name, t); } } private static byte[] read(File file) throws IOException { InputStream in = null; try { in = new BufferedInputStream(new FileInputStream(file), BUFFER_SIZE); ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] buf = new byte[BUFFER_SIZE]; for (int readBytes = in.read(buf); readBytes != -1; readBytes = in .read(buf)) { out.write(buf, 0, readBytes); } return out.toByteArray(); } finally { if (in != null) in.close(); } } }
2. Helloクラスの作成
次に、4種類の Hello クラスを作成する。
C:\eclipse_workspace\seasar2\classloader\bin
public class Hello { public static void shout() { System.out.println("Hello SystemClassLoader : " + Hello.class.getClassLoader()); } }
public class Hello { public static void shout() { System.out.println("Hello loader1 : " + Hello.class.getClassLoader()); } }
public class Hello { public static void shout() { System.out.println("Hello loader2 : " + Hello.class.getClassLoader()); } }
public class Hello { public static void shout() { System.out.println("Hello URLClassLoader : " + Hello.class.getClassLoader()); } }
それぞれコンパイルし、生成された class ファイルを別々のディレクトリに置く。
ここでは例として、C:\eclipse_workspace\classloader\loader1\bin,C:\eclipse_workspace\seasar2\loader2\bin
,C:\eclipse_workspace\seasar2\loader2\bin,C:\eclipse_workspace\seasar2\urlclassloader\binに置く。
つまりC:\eclipse_workspace\classloader\loader1\binはclasspathが通っている状態
まあ、
んな感じってこと。
3. テストプログラムの作成と実行
import java.io.File; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; public class Test { public static void main(String[] args) { ClassLoader loader1 = new DirectoryClassLoader( "C:\\eclipse_workspace\\seasar2\\loader1\\bin"); ClassLoader loader2 = new DirectoryClassLoader( "C:\\eclipse_workspace\\seasar2\\loader2\\bin"); URL[] urls = new URL[1]; try { urls[0] = new File( "C:\\eclipse_workspace\\seasar2\\urlclassloader\\bin") .toURI().toURL(); } catch (MalformedURLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } ClassLoader urlClassLoader = URLClassLoader.newInstance(urls); try { Class.forName("Hello").getMethod("shout").invoke(null, new Object[0]); Class.forName("Hello", true, loader1).getMethod("shout").invoke( null, new Object[0]); Class.forName("Hello", true, loader2).getMethod("shout").invoke( null, new Object[0]); Class.forName("Hello", true, urlClassLoader).getMethod("shout") .invoke(null, new Object[0]); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
なお、C:\eclipse_workspace\seasar2\classloader\binには、Test.class,Hello.class,DirectoryClassLoader.classの3つができる。
実行結果
Hello SystemClassLoader : sun.misc.Launcher$AppClassLoader@11b86e7
Hello SystemClassLoader : sun.misc.Launcher$AppClassLoader@11b86e7
Hello SystemClassLoader : sun.misc.Launcher$AppClassLoader@11b86e7
Hello SystemClassLoader : sun.misc.Launcher$AppClassLoader@11b86e7
ClassLoaderやURLClassLoaderでそのままつくるとシステムクラスローダが親になるため、Helloクラスはすべて
C:\eclipse_workspace\seasar2\classloader\bin\Hello.classから読み込まれたものになる。
- DirectoryClassLoaderのコンストラクタでsuper(null)
- URLClassLoader.newInstance(urls, null)
とやって、ブートストラップクラスローダを親にすれば、
実行結果は下記のようになる。
Hello SystemClassLoader : sun.misc.Launcher$AppClassLoader@11b86e7
Hello loader1 : DirectoryClassLoader@42e816
Hello loader2 : DirectoryClassLoader@190d11
Hello URLClassLoader : java.net.FactoryURLClassLoader@de6ced
参考: