Java Class的热替换 自定义ClassLoader加载.class

本文是java热替换的实验,参考了

Java 类的热替换 —— 概念、设计与实现http://www.ibm.com/developerworks/cn/java/j-lo-hotswapcls/index.html

之前的错误是,没有集成ClassLoader,而是直接使用了
[java]  view plain copy
  1. classloader = (URLClassLoader)ClassLoader.getSystemClassLoader();  
这个语句只适用于加载.jar
如果加载.class的话需要使用自定义的ClassLoader

[java]  view plain copy
  1. package yerasel;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.File;  
  5. import java.io.FileInputStream;  
  6. import java.io.FileNotFoundException;  
  7. import java.io.IOException;  
  8. import java.io.InputStream;  
  9. import java.io.InputStreamReader;  
  10. import java.lang.reflect.Field;  
  11. import java.lang.reflect.InvocationTargetException;  
  12. import java.lang.reflect.Method;  
  13.   
  14. import java.net.MalformedURLException;  
  15. import java.net.URL;  
  16. import java.net.URLClassLoader;  
  17. import java.util.HashSet;  
  18.   
  19. /* 
  20.  *  实现热部署,自定义ClassLoader,加载的是.class 
  21.  */  
  22. class HowswapCL extends ClassLoader {  
  23.   
  24.     private String basedir; // 需要该类加载器直接加载的类文件的基目录  
  25.     private HashSet dynaclazns; // 需要由该类加载器直接加载的类名  
  26.   
  27.     public HowswapCL(String basedir, String[] clazns) {  
  28.         super(null); // 指定父类加载器为 null  
  29.         this.basedir = basedir;  
  30.         dynaclazns = new HashSet();  
  31.         loadClassByMe(clazns);  
  32.     }  
  33.   
  34.     private void loadClassByMe(String[] clazns) {  
  35.         for (int i = 0; i < clazns.length; i++) {  
  36.             loadDirectly(clazns[i]);  
  37.             dynaclazns.add(clazns[i]);  
  38.         }  
  39.     }  
  40.   
  41.     private Class loadDirectly(String name) {  
  42.         Class cls = null;  
  43.         StringBuffer sb = new StringBuffer(basedir);  
  44.         String classname = name.replace('.', File.separatorChar) + ".class";  
  45.         sb.append(File.separator + classname);  
  46.         File classF = new File(sb.toString());  
  47.         try {  
  48.             cls = instantiateClass(name, new FileInputStream(classF),  
  49.                     classF.length());  
  50.         } catch (FileNotFoundException e) {  
  51.             // TODO Auto-generated catch block  
  52.             e.printStackTrace();  
  53.         }  
  54.         return cls;  
  55.     }  
  56.   
  57.     private Class instantiateClass(String name, InputStream fin, long len) {  
  58.         byte[] raw = new byte[(int) len];  
  59.         try {  
  60.             fin.read(raw);  
  61.             fin.close();  
  62.         } catch (IOException e) {  
  63.             // TODO Auto-generated catch block  
  64.             e.printStackTrace();  
  65.         }  
  66.   
  67.         return defineClass(name, raw, 0, raw.length);  
  68.     }  
  69.   
  70.     protected Class loadClass(String name, boolean resolve)  
  71.             throws ClassNotFoundException {  
  72.         Class cls = null;  
  73.         cls = findLoadedClass(name);  
  74.         if (!this.dynaclazns.contains(name) && cls == null)  
  75.             cls = getSystemClassLoader().loadClass(name);  
  76.         if (cls == null)  
  77.             throw new ClassNotFoundException(name);  
  78.         if (resolve)  
  79.             resolveClass(cls);  
  80.         return cls;  
  81.     }  
  82. }  
  83.   
  84. /* 
  85.  * 每隔500ms运行一次,不断加载class 
  86.  */  
  87. class Multirun implements Runnable {  
  88.     public void run() {  
  89.         try {  
  90.             while (true) {  
  91.                 // 每次都创建出一个新的类加载器  
  92.                 // class需要放在自己package名字的文件夹下  
  93.                 String url = System.getProperty("user.dir") + "/lib";// "/lib/yerasel/GetPI.jar";  
  94.                 HowswapCL cl = new HowswapCL(url,  
  95.                         new String[] { "yerasel.GetPI" });  
  96.                 Class cls = cl.loadClass("yerasel.GetPI");  
  97.                 Object foo = cls.newInstance();  
  98.                 // 被调用函数的参数  
  99.                 Method m = foo.getClass().getMethod("Output"new Class[] {});  
  100.                 m.invoke(foo, new Object[] {});  
  101.                 Thread.sleep(500);  
  102.             }  
  103.   
  104.         } catch (Exception ex) {  
  105.             ex.printStackTrace();  
  106.         }  
  107.     }  
  108. }  
  109.   
  110. public class Test {  
  111.   
  112.     public static Method initAddMethod() {  
  113.         try {  
  114.             Method add = URLClassLoader.class.getDeclaredMethod("addURL",  
  115.                     new Class[] { URL.class });  
  116.             add.setAccessible(true);  
  117.             return add;  
  118.         } catch (Exception e) {  
  119.             throw new RuntimeException(e);  
  120.         }  
  121.     }  
  122.   
  123.     public static void main(String[] args) {  
  124.   
  125.         // 热部署测试代码  
  126.         Thread t;  
  127.         t = new Thread(new Multirun());  
  128.         t.start();  
  129.     }  
  130. }  


GetPI.java内容:

[java]  view plain copy
  1. package yerasel;  
  2.   
  3. import java.io.PrintStream;  
  4.   
  5. public class GetPI  
  6. {  
  7.   public static double Darts(int n)  
  8.   {  
  9.     int k = 0;  
  10.     double x = 0.0D;  
  11.     double y = 0.0D;  
  12.     for (int i = 0; i < n; i++)  
  13.     {  
  14.       x = Math.random();  
  15.       y = Math.random();  
  16.   
  17.       if (x * x + y * y <= 1.0D)  
  18.         k++;  
  19.     }  
  20.     return 4 * k / n;  
  21.   }  
  22.   // 本热部署实验中,上面的Darts函数没有用到,请忽略  
  23.   public static void Output() {  
  24.     System.out.println("Output");  
  25.   }  
  26. }  

另一个GetPI.java只在输出时候改为aaaOutput

生成jar包的命令

[java]  view plain copy
  1. jar cvf GetPI.jar GetPI.class  

一定要注意的是:class需要放在package名字的文件夹下

本文中.class放在/lib(自定义路径)/yerasel(package名字)下。

运行时候,程序加载指定文件夹下的.class,即开始输出aaaOutput,然后手动将另外一个.class(输出Output的.class)覆盖此文件,

程序立即开始输出Output

运行结果图:



  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值