package test; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; public class DynamicLoader extends ClassLoader { private String baseDir; public DynamicLoader(String baseDir) { super(); this.baseDir = baseDir; } private String getClassFile(String className){ return baseDir+className.replace(".", "/")+".class"; } protected Class findClass(String className) throws ClassNotFoundException { Class clazz = this.findLoadedClass(className); if (null == clazz) { try { String classFile = getClassFile(className); FileInputStream fis = new FileInputStream(classFile); FileChannel fileC = fis.getChannel(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); WritableByteChannel outC = Channels.newChannel(baos); ByteBuffer buffer = ByteBuffer.allocateDirect(1024); int count = 0; while ((count = fileC.read(buffer)) > 0) { buffer.flip(); outC.write(buffer); buffer.clear(); } fis.close(); byte[] bytes = baos.toByteArray(); clazz = defineClass(className, bytes, 0, bytes.length); } catch (Exception e) { System.out.println("can not load class "+className +" from DynamicLoader."); } } return clazz; } protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { // First, check if the class has already been loaded
Class re=findClass(name); if(re==null){ return super.loadClass(name,resolve); } return re; } }
package test; public class Worker { public void doit(){ System.out.println("I am version 3"); } }
package test; import java.lang.reflect.Method; public class HelloMain { public static void main(String[] args) throws Exception { while(true) { DynamicLoader loader = new DynamicLoader("F:\\workspace\\HibernateSrc\\bin\\"); Class clazz = loader.loadClass("test.Worker"); Object instance = clazz.newInstance(); Method doit = clazz.getDeclaredMethod("doit",null); doit.invoke(instance, null); Thread.sleep(2000); } } }
思路:
在HelloMain里面定時的創建新的自定義ClassLoader,然后指定加載某個目錄的class文件.加載的時候不是父類優先,而是子類優先模式.
自定義的ClassLoader找到Worker類后,反射穿件實例.
這里不能用new關鍵字在HelloMain類里面創建Worker實例,也能讓反射生成的實例轉型成Worker類型,因為那樣會導致AppliationClassLoader加載Worker類.
如果被AppliationClassLoader加載了Worker類,那么新版本的Worker就不能再被Application ClassLoader加載了,一個ClassLoader里面同名的class只能有一個.
如果這個時候讓AppliationClassLoader加載了老的Worker類,在替換的時候讓自定義ClassLoader加載新版本的Woker類,則會出現ClassCastException.
因為這些Worker類來之不同的ClassLoader,比如下面代碼會報ClassCastException.
DynamicLoader loader = new DynamicLoader("F:workspaceHibernateSrcbin");
Class clazz = loader.loadClass("test.Worker");
Worker instance = (Worker)clazz.newInstance();//ClassCastException error
instance.doit();
所以Worker類只能是讓自定義的ClassLoader加載.同時下次要運行的時候,也要在創建一個新的自定義ClassLoader來加載.
參考 http://www.cnblogs.com/princessd8251/articles/3967569.html