本文主要是根据classloader的特性,结合实际产品环境中遇到的问题,来探讨下JAVA应用中局部模块热部署的可行性。
我们知道,一些web应用提供了自动检测装载webapp的功能,但大部分的时候,就是相当于重新启动了一遍Webapp,存储在内存中的数据也会丢失,并不能灵活地满足需要。而OSGI框架,虽然也提供了模块的热部署,但为了用热部署而将应用限制在OSGI的框框中,有些时候得不偿失。于是想根据实际需要来定制classloader,灵活地指定哪些类重载,哪些类不需要。
言归正传,进行我们的实践,这里先简单介绍下JAVA的classloader机制:
从上图可以看出虚拟机中的Classloader的层次结构, 由最外层的Classloader去load全限定名指定的class,如果load不到,则委托给该classloader的父classloader,直至到root classloader。
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 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);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
这里我们的自定义Classloader可以通过重载loadClass方法,仅对指定package下的类进行加载,其余全部委托父Classloader来加载 , 这里需要用到classloader的defineClass方法,以便我们的classloader可以载入任意指定位置的class文件。
public class MyClassLoader extends ClassLoader{
public static ConcurrentHashMap<String, Class<?>> classes = new ConcurrentHashMap<String, Class<?>>();
public static MqClassLoader instance = new MyClassLoader();
//构造自定义Classloader, 并指定父Classloader
public MyClassLoader() {
super(Thread.currentThread().getContextClassLoader());
}
public Class<?> load(String name, byte[] data, boolean resolve) {
Class<?> klass = defineClass(name, data, 0, data.length);
if (resolve)
resolveClass(klass);
classes.put(name, klass);
return klass;
}
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Object value = classes.get(name); // 检查缓存
if (value != null && value != INVALID) {
Class<?> klass = (Class<?>) value;
if (resolve)
resolveClass(klass);
return klass;
} else { // 缓存中不存在
byte[] data = read(findClassFile(name)); // 读取类文件
if (data == null)
return super.loadClass(name, resolve); // 交由父classloader去load类文件
else {
try {
lock.lock();
Object cc = classes.get(name); // 检查缓存
if (cc != null) {
return (Class<?>) cc;
} else
return instance.load(name, data, resolve); // 自己load类文件
} finally {
lock.unlock();
}
}
}
}
}
上面的代码描述了自定义classloader的载入逻辑,findClassFile() 就是自己定义的从哪里找需要的类文件方法。
defineClass 方法可以灵活地用来实现分布式动态计算,hadoop mapreduce应该就是使用了这一方法来保证服务器集群间的处理类的传输和运行。
/**
* 重新初始化,以便实现重载所指定的类
*/
public static void reset() {
instance = new MyClassLoader();
classes.clear();
}
其实每次reset都会产生一个新的classloader实例, 该实例会在所有这个实例装载的的类全部被回收后才被回收,这里比较奔放的全部reset掉,经过测试尚未发现内存溢出问题。
调用这些类的方法:
public static void invoke(String method ,Object[] obj, Class<?>[] parameterTypes){
try {
Object cls = MyClassLoader.instance.loadClass("类全限定名", true).newInstance();
cls.getClass().getMethod(method,parameterTypes).invoke(cls ,obj);
} catch (Exception e) {
logger.error("reloadable error " + method, e);
}
}
这里只能通过反射的方式调用,由于classloader的安全机制,同样的类,父classloader装载的类 和 子classloader装载的类不能互相转换。
需要强调的是,被重载的类重载后所有的变量都会被重新初始化,因此一些重要数据变量还是得交由父Classloader来管理。
该方式存在一些缺点,把核心逻辑归并到一起,将变量分离出去,从而影响了应用本身的结构。
目前这种方式正应用在一个消息服务中,主要避免由于一些微小的改动而重新启动服务,重启消息服务这对于大型系统来说是很麻烦的 ,是否值得还很难说,权当对java的深入学习吧。
分享到:
相关推荐
自定义classloader的使用
让Java支持热加载是个不错的想法。如何做到的呢? 1. 定义好接口和实现类 2. 让代理类通过反射的方式调用实现类,对外暴露的...Java实现热加载; Java动态加载class; Java覆盖已加载的class; Java自定义classloader;
Java 自定义ClassLoader 实现类的热替换核心代码
破解java加密的ClassLoader.java,在classloader植入破解代码
java自定义类加载classloader文档,包括代码,以及详细的原理及过程
java应用程序类加载器(ClassLoader for java Application),类似exe4j, 方便启动java程序, 配置灵活,支持多平台选择性配置
eclipse工程格式 博文链接:https://aga.iteye.com/blog/200818
热修复和插件化是目前比较热门的技术,要想更好的掌握它们需要了解ClassLoader,下面这篇文章主要给大家介绍了关于Android中自定义ClassLoader耗时问题追查的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧
ClassLoader运行机制 自己写的ClassLoader运行机制 自己写的ClassLoader运行机制 自己写的ClassLoader运行机制 自己写的ClassLoader运行机制 自己写的
博文链接:https://kuangbaoxu.iteye.com/blog/206472
Java中ClassLoader的解析,从ClassLoader的角度分析了JVM,装载类,创建类的对象的整个过程,更清晰的了解JVM的运行机制。
Java ClassLoader定制实例
classloader 源码,自定义classloader
java classloader classpath 张孝祥
这篇文章主要讲类加载器在android中如何动态的加载其他工程类的过程,对于类加载器的知识就跳过了。
自定义 ClassLoader 加载任何类时的类名。 ":myCommand" 命令位于默认 REPL 命令之上。 scala > val hello = " hello " MyClassLoader loads classOf < root>.$line3 <<中略>> MyClassLoader loads classOf ...
1.java classloader 的概述 2.java classloader 的分类 3.自定义 java classloader
内容简介: ClassLoader体系结构 类装载器在JVM中并不是唯一的,JVM自带了三个装载器,用户也可以根据自己的需求自定义新的装载器,这些装载器的体系结构可以看作是树状结构,如图1所示:
自定义ClassLoader,控制台输入调试。 运行期间 重新载入指定目录的class文件。可实现对于类的功能函数更新。 用到java 反射,@interface 等技术