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中Arrays类和Collections类常用方法示例详解

《Java中Arrays类和Collections类常用方法示例详解》本文总结了Java中Arrays和Collections类的常用方法,涵盖数组填充、排序、搜索、复制、列表转换等操作,帮助开发者高... 目录Arrays.fill()相关用法Arrays.toString()Arrays.sort()A

Spring Boot Maven 插件如何构建可执行 JAR 的核心配置

《SpringBootMaven插件如何构建可执行JAR的核心配置》SpringBoot核心Maven插件,用于生成可执行JAR/WAR,内置服务器简化部署,支持热部署、多环境配置及依赖管理... 目录前言一、插件的核心功能与目标1.1 插件的定位1.2 插件的 Goals(目标)1.3 插件定位1.4 核

如何使用Lombok进行spring 注入

《如何使用Lombok进行spring注入》本文介绍如何用Lombok简化Spring注入,推荐优先使用setter注入,通过注解自动生成getter/setter及构造器,减少冗余代码,提升开发效... Lombok为了开发环境简化代码,好处不用多说。spring 注入方式为2种,构造器注入和setter

使用zip4j实现Java中的ZIP文件加密压缩的操作方法

《使用zip4j实现Java中的ZIP文件加密压缩的操作方法》本文介绍如何通过Maven集成zip4j1.3.2库创建带密码保护的ZIP文件,涵盖依赖配置、代码示例及加密原理,确保数据安全性,感兴趣的... 目录1. zip4j库介绍和版本1.1 zip4j库概述1.2 zip4j的版本演变1.3 zip4

Java堆转储文件之1.6G大文件处理完整指南

《Java堆转储文件之1.6G大文件处理完整指南》堆转储文件是优化、分析内存消耗的重要工具,:本文主要介绍Java堆转储文件之1.6G大文件处理的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言文件为什么这么大?如何处理这个文件?分析文件内容(推荐)删除文件(如果不需要)查看错误来源如何避

SpringBoot整合Dubbo+ZK注册失败的坑及解决

《SpringBoot整合Dubbo+ZK注册失败的坑及解决》使用Dubbo框架时,需在公共pom添加依赖,启动类加@EnableDubbo,实现类用@DubboService替代@Service,配... 目录1.先看下公共的pom(maven创建的pom工程)2.启动类上加@EnableDubbo3.实

SpringBoot整合(ES)ElasticSearch7.8实践

《SpringBoot整合(ES)ElasticSearch7.8实践》本文详细介绍了SpringBoot整合ElasticSearch7.8的教程,涵盖依赖添加、客户端初始化、索引创建与获取、批量插... 目录SpringBoot整合ElasticSearch7.8添加依赖初始化创建SpringBoot项

JAVA覆盖和重写的区别及说明

《JAVA覆盖和重写的区别及说明》非静态方法的覆盖即重写,具有多态性;静态方法无法被覆盖,但可被重写(仅通过类名调用),二者区别在于绑定时机与引用类型关联性... 目录Java覆盖和重写的区别经常听到两种话认真读完上面两份代码JAVA覆盖和重写的区别经常听到两种话1.覆盖=重写。2.静态方法可andro

MySQL 主从复制部署及验证(示例详解)

《MySQL主从复制部署及验证(示例详解)》本文介绍MySQL主从复制部署步骤及学校管理数据库创建脚本,包含表结构设计、示例数据插入和查询语句,用于验证主从同步功能,感兴趣的朋友一起看看吧... 目录mysql 主从复制部署指南部署步骤1.环境准备2. 主服务器配置3. 创建复制用户4. 获取主服务器状态5

SpringBoot中六种批量更新Mysql的方式效率对比分析

《SpringBoot中六种批量更新Mysql的方式效率对比分析》文章比较了MySQL大数据量批量更新的多种方法,指出REPLACEINTO和ONDUPLICATEKEY效率最高但存在数据风险,MyB... 目录效率比较测试结构数据库初始化测试数据批量修改方案第一种 for第二种 case when第三种