オレオレHotReloading

以前から興味があったHotReloadingを実装してみた。
全然完璧じゃないけど。


とりあえずGitHubあげてる。


で、やってみた感想ですが、バヤい。これはバヤい。
かなりハマる。だだハマりした。


とりあえず軽くハマった点。


Java言語仕様とJava仮想マシン仕様は軽くでも読んでおいたほうがよい」


これに尽きる。

  • どうやってJVMがクラスをローディングするの?
  • セキュリティーってどうなってんの?

これが分かれば(まだ分かってないけど)HotReloadingも夢じゃないはず。


ソースコードは以下のようなこんな感じ。

■試しかた。
Mainを実行すると入力待ちになり、Enterを押すとhello.Sample#executeが実行される。
それが延々と繰り返されるので入力待ちの間にexecuteメソッドを変更すると、executeから出力される内容が変わる。

package hello;

import hello.classloader.CustomClassLoader;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Method;

public class Main {

	public static void main(String[] args) throws Exception {
		Main main = new Main();
		main.run();
	}

	public void run() throws Exception {
		while (true) {
			BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
			// Initialize ClassLoader
			CustomClassLoader loader = new CustomClassLoader();
			
			System.out.println(">>> Please hit the Enter key.");
			reader.readLine();
			String input = "hello.Sample execute"; 
			String[] str = input.split(" ");
			String className = str[0];
			String methodName = str[1];
			
			System.out.println("===== " + input + " =====");
			
			Class<?> clazz = loader.loadClass(className);
			Object newInstance = clazz.newInstance();
			Method method = clazz.getDeclaredMethod(methodName);
			method.invoke(newInstance);
			
			System.out.println("<<<");
			System.out.println();
		}
	}
}
package hello;

public class Sample {

	public void execute(){
		System.out.println("Hello Hot Reloading!!");
	}
}
package hello.classloader;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class CustomClassLoader extends ClassLoader {

	@Override
	public Class<?> loadClass(String className) throws ClassNotFoundException {
		if(className.startsWith("java")){
			return Class.forName(className);
		}
		int idx = className.lastIndexOf('.');
		if (idx >= 0) {
			// Defines the package
			String packageName = className.substring(0, idx);
			if (getPackage(packageName) == null) {
				try {
					definePackage(packageName, 
					null, null, null, null, null,null, null);
				} catch (IllegalArgumentException ignore) {
				}
			}
			Class<?> clazz = defineClass(className);
			if (clazz != null) {
				return clazz;
			}
		}

		return super.loadClass(className);
	}

	protected Class<?> defineClass(String className) {
		Class<?> clazz;
		String path = className.replace('.', '/') + ".class";
		InputStream is = getInputStream(path);
		if (is != null) {
			byte[] bytes = getBytes(is);
			clazz = defineClass(className, bytes, 0, bytes.length);
			resolveClass(clazz);
			return clazz;
		}
		return null;
	}
	
	protected InputStream getInputStream(String path) {
        try {
            URL url = getResource(path);
            if (url == null) {
                return null;
            }
            URLConnection connection = url.openConnection();
            connection.setUseCaches(false);
            return connection.getInputStream();
        } catch (IOException ignore) {
            return null;
        }
    }
	
	protected byte[] getBytes(InputStream is) {
        byte[] bytes = null;
        byte[] buf = new byte[8192];
        try {
            try {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                int n = 0;
                while ((n = is.read(buf, 0, buf.length)) != -1) {
                    baos.write(buf, 0, n);
                }
                bytes = baos.toByteArray();
            } finally {
                if (is != null) {
                    is.close();
                }
            }
        } catch (IOException ignore) {
        }
        return bytes;
    }
}

クラスローダーはSlim3を参考にしまくって一部そのままのメソッドもあり〼。
とりあえずSlim3すごい。読むのと書くのじゃ大違い。


以下、参考までに。

【クラスローディングの仕組み】
http://java.sun.com/docs/books/jls/third_edition/html/execution.html
http://www.ibm.com/developerworks/jp/websphere/library/java/j2ee_classloader/1.html

Javaのセキュリティー】
http://java.sun.com/javase/ja/6/docs/ja/technotes/guides/security/spec/security-spec.doc1.html#18313
http://java.sun.com/javase/ja/6/docs/ja/technotes/guides/security/spec/security-specTOC.fm.html