去年有一款产品“jrebel”可以实现运行时的类重新加载(包括方法的新增和删除),大家都知道JVM使用Application ClassLoader来加载放在classpath下的类,而且只加载一次下次在访问就会从缓存中取,所以要实现类重载只能是重新创建一个新的ClassLoader在来加载变化后的class。
问题:
1、JVM是在什么时候创建类的ClassLoader
2、创建自己的ClassLoader没什么问题,但是创建后的ClassLoader如何注册到JVM中呢?不知道有没有JVM的高手可以解答这个问题注意:此贴并是不讨论如何创建自定义的ClassLoader,而是需要一个JVM的钩子能够实现的需要时自动创建ClassLoader来达到类的重新加载的功能。
问题:
1、JVM是在什么时候创建类的ClassLoader
2、创建自己的ClassLoader没什么问题,但是创建后的ClassLoader如何注册到JVM中呢?不知道有没有JVM的高手可以解答这个问题注意:此贴并是不讨论如何创建自定义的ClassLoader,而是需要一个JVM的钩子能够实现的需要时自动创建ClassLoader来达到类的重新加载的功能。
解决方案 »
- 一个赋值语句的问题
- 问个数学问题,好像跟概率有关
- jfreereport和java的C/S混合使用,谁有这方面的资料?急!!
- 乱码问题 求救!!!!!
- [讨论]大家一般用java开发什么类型的软件
- 简单问题
- 我想用Java查看系统的CPU,内存,硬盘的相关情况,请教!!
- 有在Linux下学Java的吗?
- 在javamail-1.2中有javadocs和sundocs,在sundoc中有com.sun.mail.pop3等的介绍,为什么会分为javadocs和sundocs两个?他们各自的作用?(我不
- 菜鸟询问一个关于datainputstream的问题
- 哪位大侠知道 window压缩 linux解压缩 java程序解压缩出来的文件带%5C是怎么回事?
- 另一道腾讯的面试题
------extloader扩展
你要在用个加载类的话一般是系统加载类的子类,如要它指定是加载一个test类, 当这个test类改变后你想热改变这时你不能用这个类了,应为他以存有test类的信息不会在去加载,你可以在new一个类加载由systemloader做父加裁器。在加载test。返回class 在new出来就成了改变后的类了
try {
Method method = sysclass.getDeclaredMethod("addURL", new Class[] { URL.class });
method.setAccessible(true);
method.invoke(sysLoader, u);
} catch (Throwable t) {
t.printStackTrace();
}
cl = new URLClassLoader(externalURLs);
catClass = cl.loadClass("com.unmi.CatImpl");
// Get the directory (URL) of the reloadable class
URL[] urls = null;
try {
// Convert the file object to a URL
File dir = new File(System.getProperty("user.dir")
+File.separator+"dir"+File.separator);
URL url = dir.toURL(); // file:/c:/almanac1.4/examples/
urls = new URL[]{url};
} catch (MalformedURLException e) {
}try {
// Create a new class loader with the directory
ClassLoader cl = new URLClassLoader(urls); // Load in the class
Class cls = cl.loadClass("MyReloadableClassImpl"); // Create a new instance of the new class
myObj = (MyReloadableClass)cls.newInstance();
} catch (IllegalAccessException e) {
} catch (InstantiationException e) {
} catch (ClassNotFoundException e) {
}
u.registerRebelClassLoader((URLClassLoader)ClassLoader.getSystemClassLoader());
p.registerRebelClassLoader((URLClassLoader)ClassLoader.getSystemClassLoader());
//registerRebelClassLoader定义
public static void registerRebelClassLoader(URLClassLoader urlclassloader)
{
if(!REBEL_CLASSLOADER_MAP.containsKey(urlclassloader))
REBEL_CLASSLOADER_MAP.put(urlclassloader, new do(urlclassloader));
}
jrebel的方式是用java -javaagent参数指定的,类加载不是在classloader上做的。
在java1.5以后,增加了java -javaagent参数,提供了一个动态替换class的方式。
以jrebel为例:运行参数为java -javaagent jrebel.jar
在jrebel.jar里的META-INF目录下的MANIFEST.MF文件中定义Premain-Class
Premain-Class: com.zeroturnaround.javarebel.java5.AgentInstall该class包含一个 public static void premain(String agentArgs, Instrumentation inst)
的方法作为入口。
在java.lang.instrument.Instrumentation中提供具体的动态替换功能。
当然,要做到动态替换class,还要有class更新监控的功能。
相关知识在API文档中Package java.lang.instrument 及其子目录下有详细的介绍(JDK1.5以后)。
而且一般的加载方式是,在默认classloader里面有一个接口或者父类。
然后用自定义的加载器加载 要热加载的类。然后把 这个类 实例化转换为 父类或者接口。具体的应该是,有一个静态方法,这个方法返回一个 默认classloader 已经加载了 的接口或父类 的实例。
然后静态方法首先检查 文件是否已经更新,已经更新就生成一个新的 classloader 加载这个 新的class,然后返回新的实例。如果 默认classloader 里面没有接口或者父类,那就只能返回Object,然后用反射调用具体的方法。这时候用脚本编写比较方便。
如果不想一个一个的用 静态方法实例化。
可以 看看 Thread.setContextClassLoader。
这时候可以用 new.
不过必须得对 线程控制好。
我们通过java中的IO类动态生成.java文件。然后通过Tomcat中的动态编译和加载功能进行加载。没有试过,但是最近在看Tomcat的源码,都是java写的。
一定可行。
http://blog.csdn.net/ThirstyCrow/archive/2008/10/30/3185018.aspx
可以搜一下这个VirtualMachine,Instrumentation,很强大,可以attach到指定的虚拟机上,指定agent,在agent里面进行实现拦截器,重新加载。jdk自带的tool.jar里面的类。
现在很多Java框架如Spring都实现有拦截器,不管是基于动态代理还是Asm那样的直接修改字节码。
JVM有个插件可以帮助你实现类的重加载~ 是什么插件???有没有人研究过jrebel,可以谈谈心得
AgentInstall利用Instrumentation进行拦截,TransformNew把自己new出来的对象就行修改,实际new出来的对象已经是jrebel可以控制的对象了.jrebel用的是bytecode的修改
bootstrap classloader , extension classloader , system classloader2.而且要知道,classloader 有一种全盘负责委托机制,也就是说,cl要载入一个class的时候,这个class所依赖的所有class都要由这个classloader载入,除非是你显示的让另一个cl载入。而且委托机制是先让父加载器寻找,要是父加载器找不到的时候,在从自己的类路径中寻找。这样的话,要是想动态载入class的话,是不是可以这样处理:
比如我们要动态加载一个class,名字为 A ,我们可以构造一个A的父类,叫AParent,然后把AParent放在CLASSPATH下(system classloader加载的类路径),父类由system classloader载入,当我们用自己的classloader动态载入A的时候,发现他有个爹...在载入他之前,jvm会先载入他爹..要由system classloader载入。根据多态,调用AParent方法的时候,其实是调用的A的方法。
说的可能不对,大家带着批判的眼光来看,期待高手的解答,别让我脑子里面记得东西都是错误的东西。
感觉楼在推销这个啊