class卸载、热替换和Tomcat的热部署的分析
这篇文章主要是分析Tomcat中关于热部署和JSP更新替换的原理,在此之前先介绍class的热替换和class的卸载的原理。
一 class的热替换
ClassLoader中重要的方法
loadClass
ClassLoader.loadClass(...) 是ClassLoader的入口点。当一个类没有指明用什么加载器加载的时候,JVM默认采用AppClassLoader加载器加载没有加载过的class,调用的方法的入口就是loadClass(...)。如果一个class被自定义的ClassLoader加载,那么JVM也会调用这个自定义的ClassLoader.loadClass(...)方法来加载class内部引用的一些别的class文件。重载这个方法,能实现自定义加载class的方式,抛弃双亲委托机制,但是即使不采用双亲委托机制,比如java.lang包中的相关类还是不能自定义一个同名的类来代替,主要因为JVM解析、验证class的时候,会进行相关判断。
defineClass
系统自带的ClassLoader,默认加载程序的是AppClassLoader,ClassLoader加载一个class,最终调用的是defineClass(...)方法,这时候就在想是否可以重复调用defineClass(...)方法加载同一个类(或者修改过),最后发现调用多次的话会有相关错误:
...
java.lang.LinkageError
attempted duplicate class definition
...
所以一个class被一个ClassLoader实例加载过的话,就不能再被这个ClassLoader实例再次加载(这里的加载指的是,调用了defileClass(...)放方法,重新加载字节码、解析、验证。)。而系统默认的AppClassLoader加载器,他们内部会缓存加载过的class,重新加载的话,就直接取缓存。所与对于热加载的话,只能重新创建一个ClassLoader,然后再去加载已经被加载过的class文件。www.zzzyk.com
下面看一个class热加载的例子:
代码:HotSwapURLClassLoader自定义classloader,实现热替换的关键
1 package testjvm.testclassloader;
2
3 import java.io.File;
4 import java.io.FileNotFoundException;
5 import java.net.MalformedURLException;
6 import java.net.URL;
7 import java.net.URLClassLoader;
8 import java.util.HashMap;
9 import java.util.Map;
10
11 /**
12 * 只要功能是重新加载更改过的.class文件,达到热替换的作用
13 * @author banana
14 */
15 public class HotSwapURLClassLoader extends URLClassLoader {
16 //缓存加载class文件的最后最新修改时间
17 public static Map<String,Long> cacheLastModifyTimeMap = new HashMap<String,Long>();
18 //工程class类所在的路径
19 public static String projectClassPath = "D:/Ecpworkspace/ZJob-Note/bin/";
20 //所有的测试的类都在同一个包下
21 public static String packagePath = "testjvm/testclassloader/";
22
23 private static HotSwapURLClassLoader hcl = new HotSwapURLClassLoader();
24
25 public HotSwapURLClassLoader() {
26 //设置ClassLoader加载的路径
27 super(getMyURLs());
28 }
29
30 public static HotSwapURLClassLoader getClassLoader(){
31 return hcl;
32 }
33
34 private static URL[] getMyURLs(){
35 URL url = null;
36 try {
37 url = new File(projectClassPath).toURI().toURL();
38 } catch (MalformedURLException e) {
39 e.printStackTrace();
40 }
41 return new URL[] { url };
42 }
43
44 /**
45 * 重写loadClass,不采用双亲委托机制("java."开头的类还是会由系统默认ClassLoader加载)
46 */
47 @Override
48 public Class<?> loadClass(String name,boolean resolve) throws ClassNotFoundException {
49 Class clazz = null;
50 //查看HotSwapURLClassLoader实例缓存下,是否已经加载过class
51 //不同的HotSwapURLClassLoader实例是不共享缓存的
52 clazz = findLoadedClass(name);
53 if (clazz != null ) {
54 if (resolve){
55 resolveClass(clazz);
56 }
57 //如果class类被修改过,则重新加载
58 if (isModify(name)) {
59 hcl = new HotSwapURLClassLoader();
60 clazz = customLoad(name, hcl);
61 }
62 return (clazz);
63 }
64
65 //如果类的包名为"java."开始,则有系统默认加载器AppClassLoader加载
66 if(name.startsWith("java.")){
67 try {
68 //得到系统默认的加载cl,即AppClassLoader
69 ClassLoader system = ClassLoader.getSystemClassLoader();
70 clazz = system.loadClass(name);
71 if (clazz != null) {
72 if (resolve)
73 resolveClass(clazz);
74 return (clazz);
75 }
76 } catch (ClassNotFoundException e) {
补充:综合编程 , 其他综合 ,