Edited at

カスタムクラスローダを作ってみる

More than 5 years have passed since last update.

ホットデプロイとかそういうのに興味が湧いたのでクラスローダとか触ってみます。


MyClassLoader.java

import java.io.BufferedInputStream;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

public class MyClassLoader extends ClassLoader {

public static void main(String[] args) {
for (String arg : args) {
File classFile = new File(arg);
String className = classFile.getName().replace(".class", "");
MyClassLoader loader = new MyClassLoader(classFile, className);
try {
Class<?> clazz = Class.forName(className, true, loader);
System.out.printf("load class: %s\n", clazz.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}

private final File file;
private final String name;

public MyClassLoader(File file, String name) {
super();
this.file = file;
this.name = name;
}

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (!name.equals(this.name)) {
return super.findClass(name);
}
byte[] data = loadClassData();
return defineClass(name, data, 0, data.length);
}

private byte[] loadClassData() {
byte[] data = new byte[(int) file.length()];
try {
InputStream input = new BufferedInputStream(new FileInputStream(file));
try {
input.read(data);
} finally {
input.close();
}
} catch (FileNotFoundException e) {
throw new IllegalArgumentException(e);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
return data;
}
}

とりあえずclassファイルのFileオブジェクトとクラス名を与えると、そのクラス名でクラスを読み込めるようになるクラスローダを作成。


MyClass.java

public class MyClass {

static {
System.out.println("loaded MyClass");
}
}

ロードされると標準出力に文字を出力するだけのクラスを用意。


実行結果

$ javac *.java

両方ともコンパイルだけして

$ mkdir myclasses

$ mv MyClass.class myclasses

MyClass.classはクラスパスには入っていないディレクトリに移動。

$ java MyClassLoader myclasses/MyClass.class

loaded MyClass
load class: MyClass

引数で与えると、クラスパスには入っていないMyClass.classが読み込めている。


参考サイト