Java Class的热替换 自定义ClassLoader加载.class(java热部署实现 )

2024-03-13 03:48

本文主要是介绍Java Class的热替换 自定义ClassLoader加载.class(java热部署实现 ),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文地址:http://blog.csdn.net/wangxin1982314/article/details/65443335

本文是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

运行结果图:



这篇关于Java Class的热替换 自定义ClassLoader加载.class(java热部署实现 )的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/803551

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

ElasticSearch+Kibana通过Docker部署到Linux服务器中操作方法

《ElasticSearch+Kibana通过Docker部署到Linux服务器中操作方法》本文介绍了Elasticsearch的基本概念,包括文档和字段、索引和映射,还详细描述了如何通过Docker... 目录1、ElasticSearch概念2、ElasticSearch、Kibana和IK分词器部署

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程