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中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三