Java动态重新加载Class
项目中使用到了动态重新加载Class的机制,作用是让一些代码上线之前可以在线上环境测试一下,当然,这是非常不好的测试机制,我刚来的时候也为这种机制感到惊讶—怎么可以在线上环境运行测试代码!后来经过了解,这么做的原因有以下两个:
- 有些代码没有办法在本地进行测试,本地没有线上的环境
- 我们弱到连测试机都没有(这是重点)
既然我们连测试机都没有,那么我就觉得我们的项目其实也没有想象中的重要,这么测就这么测吧~~
之前对ClassLoader没啥概念,google到一篇文章,翻译了一下并且做了一些补充,加深记忆
原文地址:
引用
http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html#classloader
---------------------------------------------------
ClassLoader
顾名思义,ClassLoader就是用来Load Class的,当一个Class被加载的时候,这个Class所引用到的所有Class也会被加载,而且这种加载是递归的,也就是说,如果A引用到B,B 引用到C,那么当A被加载的时候,B也会被加载,而B被加载的时候,C也会加载。如此递归直到所有需要的Class都加载好。
常见的ClassLoader:
引用
* Bootstrap class loader:虚拟机运行时必须要用到的类的加载器,比如java.*。它通常是在虚拟机种用本地代码(如C)实现,在系统中用null表示。
* Extension class loader:负责加载ext目录下的Class。
* Application class loader:负责加载CLASSPATH上的类。
ClassLoader的代理层次关系
ClassLoader是以层次关系组织起来的,当你创建一个标准的Java ClassLoader的时候,你必须提供一个父ClassLoader。当一个ClassLoader需要加载一个Class的时候,它首先会让父 ClassLoader去加载这个Class,如果父ClassLoader不能加载这个Class,那么当前的ClassLoader才会自己去加载。
ClassLoader加载Class的步骤:
- 检查这个Class是否已经被加载过了
- 如果没有被加载过,那么让父ClassLoader尝试去加载
- 如果父ClassLoader无法加载,那么尝试使用当前ClassLoader加载
从ClassLoader加载Class的步骤可以得知,如果你需要动态重新加载一个Class,那么你的ClassLoader必须跟上述标准流程有所区别,需要动态加载的Class不能交给父ClassLoader,否则你自己的ClassLoader将没有机会去加载这个Class(因为正常情况下父ClassLoader总是能加载到你所请求的Class)。
所以,如果你需要ClassLoader重新加载一个Class,重写findClass方法是起不到效果的,因为findClass在父 ClassLoader加载失败之后才会执行
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
必须重写loadClass方法才能达到效果。
动态重新加载Class
Java内置的ClassLoader总会在加载一个Class之前检查这个Class是否已经被加载过,已经被加载过的Class不会加载第二次。因此要想重新加载Class,我们需要实现自己的ClassLoader。
另外一个问题是,每个被加载的Class都需要被链接(link),这是通过执行ClassLoader.resolve()来实现的,这个方法是 final的,因此无法重写。Resove()方法不允许一个ClassLoader实例link一个Class两次,因此,当你需要重新加载一个 Class的时候,你需要重新New一个你自己的ClassLoader实例。
刚才说到一个Class不能被一个ClassLoader实例加载两次,但是可以被不同的ClassLoader实例加载,这会带来新的问题:
MyObject object = (MyObject)
myClassReloadingFactory.newInstance("com.jenkov.MyObject");
这段代码会导致一个ClassCastException,因为在一个Java应用中,Class是根据它的全名(包名+类名)和加载它的 ClassLoader来唯一标识的。在上面的代码中object对象对应的Class和newInstance返回的实例对应的Class是有区别的:
| 全名 | ClassLoader实例 |
Object对象的Class | com.jenkov.MyObject | AppClassLoader实例 |
newInstance返回对象的Class | com.jenkov.MyObject | 自定义ClassLoader实例 |
解决的办法是使用接口或者父类,只重新加载实现类或者子类即可。
MyObjectInterface object = (MyObjectInterface)
myClassReloadingFactory.newInstance("com.jenkov.MyObject");
MyObjectSuperclass object = ( MyObjectSuperclass)
myClassReloadingFactory.newInstance("com.jenkov.MyObject");
在自己实现的ClassLoader中,当需要加载MyObjectInterface或者MyObjectSuperclass的时候,要代理给父 ClassLoader去加载。
实例代码就不贴了,可以去原作者网站上去看,动态重新加载Class可以做成当Class文件有修改的时候就重新加载(比如根据文件大小+修改时间或者算个文件md5值)。
分享到:
相关推荐
这篇博客“Java类动态加载(一)——java源文件动态编译为class文件”可能主要探讨了如何在运行时将Java源代码(.java)编译成对应的字节码文件(.class),并将其加载到Java虚拟机(JVM)中。以下是对这个主题的详细解析...
总之,Java热加载Class文件是提高开发效率的有效手段,它通过动态替换和更新类,使得开发者能够在不重启JVM的情况下观察代码更改的效果。了解并掌握这项技术,对于提升Java开发者的生产力具有重要意义。
本主题将深入探讨Java中的动态编译与热加载机制,并结合`js热加载`这一概念进行讨论。 首先,让我们理解Java的动态编译。Java源代码(.java文件)需要通过Java编译器(javac)转化为字节码(.class文件)才能被JVM...
首先,我们需要理解Java的类加载机制。Java中的类是由类加载器(ClassLoader)负责加载的。默认情况下,Java虚拟机(JVM)提供了三个内置的类加载器:启动类加载器(Bootstrap ClassLoader)、扩展类加载器...
在Java编程语言中,动态加载类机制是一种强大的功能,它允许程序在运行时根据需要加载新的类或资源,而不是在编译时确定所有类。这种技术对于提高软件的灵活性、可扩展性和模块化至关重要,特别是在大型系统和插件式...
综上所述,"springboot+java类热加载"是一个涉及SpringBoot框架、Java类加载机制、动态编译以及依赖管理的综合技术话题。通过理解这些概念和相关工具,开发者可以更高效地进行迭代开发,提高生产力。在实际应用中,...
动态加载jar包技术主要涉及Java的反射机制、类加载器和插件系统。下面我们将深入探讨这些知识点。 首先,了解Java的反射机制是理解动态加载的基础。Java反射API允许我们在运行时检查类、接口、字段和方法的信息,...
在Java编程中,动态编译字符串成Java代码并将其加载到JVM(Java虚拟机)是一种高级技巧,常用于运行时代码生成、元编程或插件系统等场景。这一技术的核心在于利用Java的反射API和Java Compiler API。下面将详细阐述...
Java动态类加载机制是Java平台一个非常重要的特性,它允许程序在运行时动态地加载类,增强了软件的灵活性和可扩展性。动态类加载对于理解和优化Java应用程序的性能、实现插件系统、以及处理复杂的模块化系统至关重要...
- JRebel通过替换Java虚拟机(JVM)的类加载机制,使得已加载的类可以被动态替换,达到热重载的效果。 3. **Tomcat自带的Class reloading** - Tomcat在开发模式下,可以通过设置`reloadable=true`在`conf/server....
在Java编程语言中,动态类加载机制是一种强大的特性,它允许程序在运行时加载、实例化和执行未在编译时硬编码的类。这种能力是通过Java的反射API实现的,它为开发者提供了深入洞察和操作Java对象的能力。本文将深入...
总之,理解并掌握如何使用ClassLoader动态加载Class是Java开发中的重要技能,它能帮助我们构建更灵活、可扩展的系统。在实现过程中,要兼顾性能、安全和可维护性,合理设计类加载策略,确保代码的高效运行。
### JAVA类加载机制与动态代理 #### 一、类加载机制 ##### 1.1 类加载的时机 类加载机制负责将描述类的数据从`.class`文件加载到内存,并进行必要的校验、转换解析和初始化,使之成为可以被Java虚拟机直接使用的...
总结来说,Java配置加载机制的关键在于抽象出加载器和提供者接口,利用泛型处理不同类型的配置数据,通过工厂模式动态创建合适的配置加载器和提供者,以实现配置的灵活加载和管理。这种设计对于大型、复杂的应用程序...
总结起来,Android 动态加载Class涉及到的关键技术包括:自定义ClassLoader、Dex文件操作、反射、权限管理以及Android的类加载机制。这一技术在提高程序灵活性和维护性的同时,也需要开发者对Android系统的深入了解...
### 深入研究Java类加载机制 #### 一、Java类加载机制概述 Java类加载机制是Java程序运行的第一步,它对于理解Java虚拟机(JVM)的行为至关重要。类加载过程涉及到类的加载、链接(验证、准备、解析)、初始化等...
这种动态加载驱动的方法不仅适用于数据库驱动,还可以应用于其他需要在运行时插入或替换功能的场景,如插件系统、服务发现机制等。它使得软件的组件化和模块化更加容易,有助于构建更健壮和可扩展的应用。 面向接口...
在Java编程中,动态加载JAR或ZIP包是一项重要的技术,它允许程序在运行时根据需求加载外部库,而不是在编译时静态地链接。这种技术对于实现插件化、模块化系统,或者处理频繁更新的组件非常有用。下面将详细讲解如何...
当使用JDBC连接某个数据库时,可以通过SPI机制动态加载相应的驱动实现。 在实现SPI机制时,通常会用到一个关键的类ServiceLoader,它加载指定的服务接口,并通过迭代器模式返回服务接口的所有实现类的实例。...
在动态加载驱动的情况下,需要自定义连接池实现以配合动态加载机制。 总结来说,Java动态加载数据库驱动的核心在于利用 `ClassLoader` 在运行时加载特定的数据库驱动类,避免了因为静态加载所有驱动而可能导致的...