ホットデプロイとかそういうのに興味が湧いたのでクラスローダとか触ってみます。
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が読み込めている。