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