classloader = (URLClassLoader)ClassLoader.getSystemClassLoader();这个语句只适用于加载.jar
package yerasel; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.HashSet; /* * 实现热部署,自定义ClassLoader,加载的是.class */ class HowswapCL extends ClassLoader { private String basedir; // 需要该类加载器直接加载的类文件的基目录 private HashSet dynaclazns; // 需要由该类加载器直接加载的类名 public HowswapCL(String basedir, String[] clazns) { super(null); // 指定父类加载器为 null this.basedir = basedir; dynaclazns = new HashSet(); loadClassByMe(clazns); } private void loadClassByMe(String[] clazns) { for (int i = 0; i < clazns.length; i++) { loadDirectly(clazns[i]); dynaclazns.add(clazns[i]); } } private Class loadDirectly(String name) { Class cls = null; StringBuffer sb = new StringBuffer(basedir); String classname = name.replace('.', File.separatorChar) + ".class"; sb.append(File.separator + classname); File classF = new File(sb.toString()); try { cls = instantiateClass(name, new FileInputStream(classF), classF.length()); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } return cls; } private Class instantiateClass(String name, InputStream fin, long len) { byte[] raw = new byte[(int) len]; try { fin.read(raw); fin.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return defineClass(name, raw, 0, raw.length); } protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { Class cls = null; cls = findLoadedClass(name); if (!this.dynaclazns.contains(name) && cls == null) cls = getSystemClassLoader().loadClass(name); if (cls == null) throw new ClassNotFoundException(name); if (resolve) resolveClass(cls); return cls; } } /* * 每隔500ms运行一次,不断加载class */ class Multirun implements Runnable { public void run() { try { while (true) { // 每次都创建出一个新的类加载器 // class需要放在自己package名字的文件夹下 String url = System.getProperty("user.dir") + "/lib";// "/lib/yerasel/GetPI.jar"; HowswapCL cl = new HowswapCL(url, new String[] { "yerasel.GetPI" }); Class cls = cl.loadClass("yerasel.GetPI"); Object foo = cls.newInstance(); // 被调用函数的参数 Method m = foo.getClass().getMethod("Output", new Class[] {}); m.invoke(foo, new Object[] {}); Thread.sleep(500); } } catch (Exception ex) { ex.printStackTrace(); } } } public class Test { public static Method initAddMethod() { try { Method add = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class }); add.setAccessible(true); return add; } catch (Exception e) { throw new RuntimeException(e); } } public static void main(String[] args) { // 热部署测试代码 Thread t; t = new Thread(new Multirun()); t.start(); } }
GetPI.java内容:
package yerasel; import java.io.PrintStream; public class GetPI { public static double Darts(int n) { int k = 0; double x = 0.0D; double y = 0.0D; for (int i = 0; i < n; i++) { x = Math.random(); y = Math.random(); if (x * x + y * y <= 1.0D) k++; } return 4 * k / n; } // 本热部署实验中,上面的Darts函数没有用到,请忽略 public static void Output() { System.out.println("Output"); } }
生成jar包的命令
jar cvf GetPI.jar GetPI.class
一定要注意的是:class需要放在package名字的文件夹下
本文中.class放在/lib(自定义路径)/yerasel(package名字)下。
运行时候,程序加载指定文件夹下的.class,即开始输出aaaOutput,然后手动将另外一个.class(输出Output的.class)覆盖此文件,
程序立即开始输出Output
运行结果图: