隨筆 - 12, 文章 - 0, 評(píng)論 - 22, 引用 - 0
          數(shù)據(jù)加載中……

          class卸載、熱替換和Tomcat的熱部署的分析

               這篇文章主要是分析Tomcat中關(guān)于熱部署和JSP更新替換的原理,在此之前先介紹class的熱替換和class的卸載的原理。

          一 class的熱替換
          ClassLoader中重要的方法
          loadClass
                ClassLoader.loadClass(...) 是ClassLoader的入口點(diǎn)。當(dāng)一個(gè)類(lèi)沒(méi)有指明用什么加載器加載的時(shí)候,JVM默認(rèn)采用AppClassLoader加載器加載沒(méi)有加載過(guò)的class,調(diào)用的方法的入口就是loadClass(...)。如果一個(gè)class被自定義的ClassLoader加載,那么JVM也會(huì)調(diào)用這個(gè)自定義的ClassLoader.loadClass(...)方法來(lái)加載class內(nèi)部引用的一些別的class文件。重載這個(gè)方法,能實(shí)現(xiàn)自定義加載class的方式,拋棄雙親委托機(jī)制,但是即使不采用雙親委托機(jī)制,比如java.lang包中的相關(guān)類(lèi)還是不能自定義一個(gè)同名的類(lèi)來(lái)代替,主要因?yàn)镴VM解析、驗(yàn)證class的時(shí)候,會(huì)進(jìn)行相關(guān)判斷。
           
          defineClass
                系統(tǒng)自帶的ClassLoader,默認(rèn)加載程序的是AppClassLoader,ClassLoader加載一個(gè)class,最終調(diào)用的是defineClass(...)方法,這時(shí)候就在想是否可以重復(fù)調(diào)用defineClass(...)方法加載同一個(gè)類(lèi)(或者修改過(guò)),最后發(fā)現(xiàn)調(diào)用多次的話會(huì)有相關(guān)錯(cuò)誤:
          ...
          java.lang.LinkageError 
          attempted duplicate class definition
          ...
          所以一個(gè)class被一個(gè)ClassLoader實(shí)例加載過(guò)的話,就不能再被這個(gè)ClassLoader實(shí)例再次加載(這里的加載指的是,調(diào)用了defileClass(...)放方法,重新加載字節(jié)碼、解析、驗(yàn)證。)。而系統(tǒng)默認(rèn)的AppClassLoader加載器,他們內(nèi)部會(huì)緩存加載過(guò)的class,重新加載的話,就直接取緩存。所與對(duì)于熱加載的話,只能重新創(chuàng)建一個(gè)ClassLoader,然后再去加載已經(jīng)被加載過(guò)的class文件。

          下面看一個(gè)class熱加載的例子:
          代碼:HotSwapURLClassLoader自定義classloader,實(shí)現(xiàn)熱替換的關(guān)鍵
            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  * 只要功能是重新加載更改過(guò)的.class文件,達(dá)到熱替換的作用
           13  * @author banana
           14  */
           15 public class HotSwapURLClassLoader extends URLClassLoader {
           16     //緩存加載class文件的最后最新修改時(shí)間
           17     public static Map<String,Long> cacheLastModifyTimeMap = new HashMap<String,Long>();
           18     //工程class類(lèi)所在的路徑
           19     public static String projectClassPath = "D:/Ecpworkspace/ZJob-Note/bin/";
           20     //所有的測(cè)試的類(lèi)都在同一個(gè)包下
           21     public static String packagePath = "testjvm/testclassloader/";
           22     
           23     private static HotSwapURLClassLoader hcl = new HotSwapURLClassLoader();
           24     
           25     public HotSwapURLClassLoader() {
           26         //設(shè)置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      * 重寫(xiě)loadClass,不采用雙親委托機(jī)制("java."開(kāi)頭的類(lèi)還是會(huì)由系統(tǒng)默認(rèn)ClassLoader加載)
           46      */
           47     @Override
           48     public Class<?> loadClass(String name,boolean resolve) throws ClassNotFoundException {
           49         Class clazz = null;
           50         //查看HotSwapURLClassLoader實(shí)例緩存下,是否已經(jīng)加載過(guò)class
           51         //不同的HotSwapURLClassLoader實(shí)例是不共享緩存的
           52         clazz = findLoadedClass(name);
           53         if (clazz != null ) {
           54             if (resolve){
           55                 resolveClass(clazz);
           56             }
           57             //如果class類(lèi)被修改過(guò),則重新加載
           58             if (isModify(name)) {
           59                 hcl = new HotSwapURLClassLoader();
           60                 clazz = customLoad(name, hcl);
           61             }
           62             return (clazz);
           63         }
           64 
           65         //如果類(lèi)的包名為"java."開(kāi)始,則有系統(tǒng)默認(rèn)加載器AppClassLoader加載
           66         if(name.startsWith("java.")){
           67             try {
           68                 //得到系統(tǒng)默認(rèn)的加載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) {
           77                 // Ignore
           78             }
           79         }
           80         
           81         return customLoad(name,this);
           82     }
           83 
           84     public Class load(String name) throws Exception{
           85         return loadClass(name);
           86     }
           87 
           88     /**
           89      * 自定義加載
           90      * @param name
           91      * @param cl 
           92      * @return
           93      * @throws ClassNotFoundException
           94      */
           95     public Class customLoad(String name,ClassLoader cl) throws ClassNotFoundException {
           96         return customLoad(name, false,cl);
           97     }
           98 
           99     /**
          100      * 自定義加載
          101      * @param name
          102      * @param resolve
          103      * @return
          104      * @throws ClassNotFoundException
          105      */
          106     public Class customLoad(String name, boolean resolve,ClassLoader cl)
          107             throws ClassNotFoundException {
          108         //findClass()調(diào)用的是URLClassLoader里面重載了ClassLoader的findClass()方法
          109         Class clazz = ((HotSwapURLClassLoader)cl).findClass(name);
          110         if (resolve)
          111             ((HotSwapURLClassLoader)cl).resolveClass(clazz);
          112         //緩存加載class文件的最后修改時(shí)間
          113         long lastModifyTime = getClassLastModifyTime(name);
          114         cacheLastModifyTimeMap.put(name,lastModifyTime);
          115         return clazz;
          116     }
          117     
          118     public Class<?> loadClass(String name) throws ClassNotFoundException {
          119         return loadClass(name,false);
          120     }
          121     
          122     @Override
          123     protected Class<?> findClass(String name) throws ClassNotFoundException {
          124         // TODO Auto-generated method stub
          125         return super.findClass(name);
          126     }
          127     
          128     /**
          129      * @param name
          130      * @return .class文件最新的修改時(shí)間
          131      */
          132     private long getClassLastModifyTime(String name){
          133         String path = getClassCompletePath(name);
          134         File file = new File(path);
          135         if(!file.exists()){
          136             throw new RuntimeException(new FileNotFoundException(name));
          137         }
          138         return file.lastModified();
          139     }
          140     
          141     /**
          142      * 判斷這個(gè)文件跟上次比是否修改過(guò)
          143      * @param name
          144      * @return
          145      */
          146     private boolean isModify(String name){
          147         long lastmodify = getClassLastModifyTime(name);
          148         long previousModifyTime = cacheLastModifyTimeMap.get(name);
          149         if(lastmodify>previousModifyTime){
          150             return true;
          151         }
          152         return false;
          153     }
          154     
          155     /**
          156      * @param name
          157      * @return .class文件的完整路徑 (e.g. E:/A.class)
          158      */
          159     private String getClassCompletePath(String name){
          160         String simpleName = name.substring(name.lastIndexOf(".")+1);
          161         return projectClassPath+packagePath+simpleName+".class";
          162     }
          163     
          164 }
          165 

          代碼:Hot被用來(lái)修改的類(lèi)
          1 package testjvm.testclassloader;
          2 
          3 public class Hot {
          4     public void hot(){
          5         System.out.println(" version 1 : "+this.getClass().getClassLoader());
          6     }
          7 }
          8 

          代碼:TestHotSwap測(cè)試類(lèi)
           1 package testjvm.testclassloader;
           2 
           3 import java.lang.reflect.Method;
           4 
           5 public class TestHotSwap {
           6 
           7     public static void main(String[] args) throws Exception {
           8         //開(kāi)啟線程,如果class文件有修改,就熱替換
           9         Thread t = new Thread(new MonitorHotSwap());
          10         t.start();
          11     }
          12 }
          13 
          14 class MonitorHotSwap implements Runnable {
          15     // Hot就是用于修改,用來(lái)測(cè)試熱加載
          16     private String className = "testjvm.testclassloader.Hot";
          17     private Class hotClazz = null;
          18     private HotSwapURLClassLoader hotSwapCL = null;
          19 
          20     @Override
          21     public void run() {
          22         try {
          23             while (true) {
          24                 initLoad();
          25                 Object hot = hotClazz.newInstance();
          26                 Method m = hotClazz.getMethod("hot");
          27                 m.invoke(hot, null); //打印出相關(guān)信息
          28                 // 每隔10秒重新加載一次
          29                 Thread.sleep(10000);
          30             }
          31         } catch (Exception e) {
          32             e.printStackTrace();
          33         }
          34     }
          35 
          36     /**
          37      * 加載class
          38      */
          39     void initLoad() throws Exception {
          40         hotSwapCL = HotSwapURLClassLoader.getClassLoader();
          41         // 如果Hot類(lèi)被修改了,那么會(huì)重新加載,hotClass也會(huì)返回新的
          42         hotClazz = hotSwapCL.loadClass(className);
          43     }
          44 }

               在測(cè)試類(lèi)運(yùn)行的時(shí)候,修改Hot.class文件 
          Hot.class
          原來(lái)第五行:System.out.println(" version 1 : "+this.getClass().getClassLoader());
          改后第五行:System.out.println(" version 2 : "+this.getClass().getClassLoader());
             
          輸出
           version 1 : testjvm.testclassloader.HotSwapURLClassLoader@610f7612
           version 1 : testjvm.testclassloader.HotSwapURLClassLoader@610f7612
           version 2 : testjvm.testclassloader.HotSwapURLClassLoader@45e4d960
           version 2 : testjvm.testclassloader.HotSwapURLClassLoader@45e4d960
               所以HotSwapURLClassLoader是重加載了Hot類(lèi) 。注意上面,其實(shí)當(dāng)加載修改后的Hot時(shí),HotSwapURLClassLoader實(shí)例跟加載沒(méi)修改Hot的HotSwapURLClassLoader不是同一個(gè)。
          圖:HotSwapURLClassLoader加載情況

               總結(jié):上述類(lèi)熱加載,需要自定義ClassLoader,并且只能重新實(shí)例化ClassLoader實(shí)例,利用新的ClassLoader實(shí)例才能重新加載之前被加載過(guò)的class。并且程序需要模塊化,才能利用這種熱加載方式。

          二 class卸載
                在Java中class也是可以u(píng)nload。JVM中class和Meta信息存放在PermGen space區(qū)域。如果加載的class文件很多,那么可能導(dǎo)致PermGen space區(qū)域空間溢出。引起:java.lang.OutOfMemoryErrorPermGen space.  對(duì)于有些Class我們可能只需要使用一次,就不再需要了,也可能我們修改了class文件,我們需要重新加載 newclass,那么oldclass就不再需要了。那么JVM怎么樣才能卸載Class呢。

                JVM中的Class只有滿足以下三個(gè)條件,才能被GC回收,也就是該Class被卸載(unload):

             - 該類(lèi)所有的實(shí)例都已經(jīng)被GC。
             - 加載該類(lèi)的ClassLoader實(shí)例已經(jīng)被GC。
             - 該類(lèi)的java.lang.Class對(duì)象沒(méi)有在任何地方被引用。


               GC的時(shí)機(jī)我們是不可控的,那么同樣的我們對(duì)于Class的卸載也是不可控的。 

          例子:
          代碼:SimpleURLClassLoader,一個(gè)簡(jiǎn)單的自定義classloader
            1 package testjvm.testclassloader;
            2 
            3 import java.io.File;
            4 import java.net.MalformedURLException;
            5 import java.net.URL;
            6 import java.net.URLClassLoader;
            7 
            8 public class SimpleURLClassLoader extends URLClassLoader {
            9     //工程class類(lèi)所在的路徑
           10     public static String projectClassPath = "E:/IDE/work_place/ZJob-Note/bin/";
           11     //所有的測(cè)試的類(lèi)都在同一個(gè)包下
           12     public static String packagePath = "testjvm/testclassloader/";
           13     
           14     public SimpleURLClassLoader() {
           15         //設(shè)置ClassLoader加載的路徑
           16         super(getMyURLs());
           17     }
           18     
           19     private static  URL[] getMyURLs(){
           20         URL url = null;
           21         try {
           22             url = new File(projectClassPath).toURI().toURL();
           23         } catch (MalformedURLException e) {
           24             e.printStackTrace();
           25         }
           26         return new URL[] { url };
           27     }
           28     
           29     public Class load(String name) throws Exception{
           30         return loadClass(name);
           31     }
           32 
           33     public Class<?> loadClass(String name) throws ClassNotFoundException {
           34         return loadClass(name,false);
           35     }
           36     
           37     /**
           38      * 重寫(xiě)loadClass,不采用雙親委托機(jī)制("java."開(kāi)頭的類(lèi)還是會(huì)由系統(tǒng)默認(rèn)ClassLoader加載)
           39      */
           40     @Override
           41     public Class<?> loadClass(String name,boolean resolve) throws ClassNotFoundException {
           42         Class clazz = null;
           43         //查看HotSwapURLClassLoader實(shí)例緩存下,是否已經(jīng)加載過(guò)class
           44         clazz = findLoadedClass(name);
           45         if (clazz != null ) {
           46             if (resolve){
           47                 resolveClass(clazz);
           48             }
           49             return (clazz);
           50         }
           51 
           52         //如果類(lèi)的包名為"java."開(kāi)始,則有系統(tǒng)默認(rèn)加載器AppClassLoader加載
           53         if(name.startsWith("java.")){
           54             try {
           55                 //得到系統(tǒng)默認(rèn)的加載cl,即AppClassLoader
           56                 ClassLoader system = ClassLoader.getSystemClassLoader();
           57                 clazz = system.loadClass(name);
           58                 if (clazz != null) {
           59                     if (resolve)
           60                         resolveClass(clazz);
           61                     return (clazz);
           62                 }
           63             } catch (ClassNotFoundException e) {
           64                 // Ignore
           65             }
           66         }
           67         
           68         return customLoad(name,this);
           69     }
           70 
           71     /**
           72      * 自定義加載
           73      * @param name
           74      * @param cl 
           75      * @return
           76      * @throws ClassNotFoundException
           77      */
           78     public Class customLoad(String name,ClassLoader cl) throws ClassNotFoundException {
           79         return customLoad(name, false,cl);
           80     }
           81 
           82     /**
           83      * 自定義加載
           84      * @param name
           85      * @param resolve
           86      * @return
           87      * @throws ClassNotFoundException
           88      */
           89     public Class customLoad(String name, boolean resolve,ClassLoader cl)
           90             throws ClassNotFoundException {
           91         //findClass()調(diào)用的是URLClassLoader里面重載了ClassLoader的findClass()方法
           92         Class clazz = ((SimpleURLClassLoader)cl).findClass(name);
           93         if (resolve)
           94             ((SimpleURLClassLoader)cl).resolveClass(clazz);
           95         return clazz;
           96     }
           97     
           98     @Override
           99     protected Class<?> findClass(String name) throws ClassNotFoundException {
          100         return super.findClass(name);
          101     }
          102 }
          103 

          代碼:A 
          1 public class A {  
          2 //  public static final Level CUSTOMLEVEL = new Level("test", 550) {}; // 內(nèi)部類(lèi)
          3 }
          代碼:TestClassUnload,測(cè)試類(lèi)
           1 package testjvm.testclassloader;
           2 
           3 public class TestClassUnLoad {
           4 
           5     public static void main(String[] args) throws Exception {
           6         SimpleURLClassLoader loader = new SimpleURLClassLoader();
           7         // 用自定義的加載器加載A
           8         Class clazzA = loader.load("testjvm.testclassloader.A");
           9         Object a = clazzA.newInstance();
          10         // 清除相關(guān)引用
          11         a = null;
          12         clazzA = null;
          13         loader = null;
          14         // 執(zhí)行一次gc垃圾回收
          15         System.gc();
          16         System.out.println("GC over");
          17     }
          18 }
          19 

                運(yùn)行的時(shí)候配置VM參數(shù): -verbose:class;用于查看class的加載與卸載情況。如果用的是Eclipse,在Run Configurations中配置此參數(shù)即可。
          圖:Run Configurations配置    


          輸出結(jié)果
          .....
          [Loaded java.net.URI$Parser from E:\java\jdk1.7.0_03\jre\lib\rt.jar]
          [Loaded testjvm.testclassloader.A from file:/E:/IDE/work_place/ZJob-Note/bin/]
          [Unloading class testjvm.testclassloader.A]
          GC over
          [Loaded sun.misc.Cleaner from E:\java\jdk1.7.0_03\jre\lib\rt.jar]
          [Loaded java.lang.Shutdown from E:\java\jdk1.7.0_03\jre\lib\rt.jar]
          ......
                上面輸出結(jié)果中的確A.class被加載了,然后A.class又被卸載了。這個(gè)例子中說(shuō)明了,即便是class加載進(jìn)了內(nèi)存,也是可以被釋放的。

          圖:程序運(yùn)行中,引用沒(méi)清楚前,內(nèi)存中情況

          圖:垃圾回收后,程序沒(méi)結(jié)束前,內(nèi)存中情況
           

              1、有啟動(dòng)類(lèi)加載器加載的類(lèi)型在整個(gè)運(yùn)行期間是不可能被卸載的(jvm和jls規(guī)范).
              2、被系統(tǒng)類(lèi)加載器和標(biāo)準(zhǔn)擴(kuò)展類(lèi)加載器加載的類(lèi)型在運(yùn)行期間不太可能被卸載,因?yàn)橄到y(tǒng)類(lèi)加載器實(shí)例或者標(biāo)準(zhǔn)擴(kuò)展類(lèi)的實(shí)例基本上在整個(gè)運(yùn)行期間總能直接或者間接的訪問(wèn)的到,其達(dá)到unreachable的可能性極小.(當(dāng)然,在虛擬機(jī)快退出的時(shí)候可以,因?yàn)椴还蹸lassLoader實(shí)例或者Class(java.lang.Class)實(shí)例也都是在堆中存在,同樣遵循垃圾收集的規(guī)則).
              3、被開(kāi)發(fā)者自定義的類(lèi)加載器實(shí)例加載的類(lèi)型只有在很簡(jiǎn)單的上下文環(huán)境中才能被卸載,而且一般還要借助于強(qiáng)制調(diào)用虛擬機(jī)的垃圾收集功能才可以做到.可以預(yù)想,稍微復(fù)雜點(diǎn)的應(yīng)用場(chǎng)景中(尤其很多時(shí)候,用戶在開(kāi)發(fā)自定義類(lèi)加載器實(shí)例的時(shí)候采用緩存的策略以提高系統(tǒng)性能),被加載的類(lèi)型在運(yùn)行期間也是幾乎不太可能被卸載的(至少卸載的時(shí)間是不確定的).
                綜合以上三點(diǎn), 一個(gè)已經(jīng)加載的類(lèi)型被卸載的幾率很小至少被卸載的時(shí)間是不確定的.同時(shí),我們可以看的出來(lái),開(kāi)發(fā)者在開(kāi)發(fā)代碼時(shí)候,不應(yīng)該對(duì)虛擬機(jī)的類(lèi)型卸載做任何假設(shè)的前提下來(lái)實(shí)現(xiàn)系統(tǒng)中的特定功能.
                 
          三 Tomcat中關(guān)于類(lèi)的加載與卸載
                  Tomcat中與其說(shuō)有熱加載,還不如說(shuō)是熱部署來(lái)的準(zhǔn)確些。因?yàn)閷?duì)于一個(gè)應(yīng)用,其中class文件被修改過(guò),那么Tomcat會(huì)先卸載這個(gè)應(yīng)用(Context),然后重新加載這個(gè)應(yīng)用,其中關(guān)鍵就在于自定義ClassLoader的應(yīng)用。這里有篇文章很好的介紹了tomcat中對(duì)于ClassLoader的應(yīng)用,請(qǐng)點(diǎn)擊here

          Tomcat啟動(dòng)的時(shí)候,ClassLoader加載的流程:
          1 Tomcat啟動(dòng)的時(shí)候,用system classloader即AppClassLoader加載{catalina.home}/bin里面的jar包,也就是tomcat啟動(dòng)相關(guān)的jar包。
          2 Tomcat啟動(dòng)類(lèi)Bootstrap中有3個(gè)classloader屬性,catalinaLoader、commonLoader、sharedLoader在Tomcat7中默認(rèn)他們初始化都為同一個(gè)StandardClassLoader實(shí)例。具體的也可以在{catalina.home}/bin/bootstrap.jar包中的catalina.properites中進(jìn)行配置。
          3 StandardClassLoader加載{catalina.home}/lib下面的所有Tomcat用到的jar包。
          4 一個(gè)Context容器,代表了一個(gè)app應(yīng)用。Context-->WebappLoader-->WebClassLoader。并且Thread.contextClassLoader=WebClassLoader。應(yīng)用程序中的jsp文件、class類(lèi)、lib/*.jar包,都是WebClassLoader加載的。

          Tomcat加載資源的概況圖:



          當(dāng)Jsp文件修改的時(shí)候,Tomcat更新步驟:
          1 但訪問(wèn)1.jsp的時(shí)候,1.jsp的包裝類(lèi)JspServletWrapper會(huì)去比較1.jsp文件最新修改時(shí)間和上次的修改時(shí)間,以此判斷1.jsp是否修改過(guò)。
          2 1.jsp修改過(guò)的話,那么jspservletWrapper會(huì)清除相關(guān)引用,包括1.jsp編譯后的servlet實(shí)例和加載這個(gè)servlet的JasperLoader實(shí)例。
          3 重新創(chuàng)建一個(gè)JasperLoader實(shí)例,重新加載修改過(guò)后的1.jsp,重新生成一個(gè)Servlet實(shí)例。
          4 返回修改后的1.jsp內(nèi)容給用戶。
          圖:Jsp清除引用和資源


          當(dāng)app下面的class文件修改的時(shí)候,Tomcat更新步驟:
          1 Context容器會(huì)有專(zhuān)門(mén)線程監(jiān)控app下面的類(lèi)的修改情況。
          2 如果發(fā)現(xiàn)有類(lèi)被修改了。那么調(diào)用Context.reload()。清楚一系列相關(guān)的引用和資源。
          3 然后創(chuàng)新創(chuàng)建一個(gè)WebClassLoader實(shí)例,重新加載app下面需要的class。
          圖:Context清除引用和資源 

               在一個(gè)有一定規(guī)模的應(yīng)用中,如果文件修改多次,重啟多次的話,java.lang.OutOfMemoryErrorPermGen space這個(gè)錯(cuò)誤的的出現(xiàn)非常頻繁。主要就是因?yàn)槊看沃貑⒅匦录虞d大量的class,超過(guò)了PermGen space設(shè)置的大小。兩種情況可能導(dǎo)致PermGen space溢出。一、GC(Garbage Collection)在主程序運(yùn)行期對(duì)PermGen space沒(méi)有進(jìn)行清理(GC的不可控行),二、重啟之前WebClassLoader加載的class在別的地方還存在著引用。這里有篇很好的文章介紹了class內(nèi)存泄露-here


          參考:
          http://blog.csdn.net/runanli/article/details/2972361(關(guān)于Class類(lèi)加載器 內(nèi)存泄漏問(wèn)題的探討)
          http://www.aygfsteel.com/zhuxing/archive/2008/07/24/217285.html(Java虛擬機(jī)類(lèi)型卸載和類(lèi)型更新解析)
          http://www.ibm.com/developerworks/cn/java/j-lo-hotswapcls/(Java 類(lèi)的熱替換 —— 概念、設(shè)計(jì)與實(shí)現(xiàn))
          http://www.iteye.com/topic/136427(classloader體系結(jié)構(gòu))

          posted on 2012-11-07 22:29 heavensay 閱讀(22694) 評(píng)論(7)  編輯  收藏 所屬分類(lèi): Java

          評(píng)論

          # re: class卸載、熱替換和Tomcat的熱部署的分析  回復(fù)  更多評(píng)論   

          分析很給力呀

          # re: class卸載、熱替換和Tomcat的熱部署的分析  回復(fù)  更多評(píng)論   

          不錯(cuò),相當(dāng)給力!!!
          2012-11-13 22:28 | Alicus

          # re: class卸載、熱替換和Tomcat的熱部署的分析  回復(fù)  更多評(píng)論   

          public class Hot {
          public void hot(TestObject to){
          System.out.println(" version 1 : "+this.getClass().getClassLoader());
          }
          熱替換的時(shí)候,在hot方法里加一個(gè)非基本類(lèi)型的類(lèi)對(duì)象參數(shù),反射的時(shí)候會(huì)找不到該方法,請(qǐng)問(wèn)這個(gè)怎么解決?
          2013-04-12 19:07 | 04

          # re: class卸載、熱替換和Tomcat的熱部署的分析  回復(fù)  更多評(píng)論   

          我去,好文章,找了好久了
          2013-08-26 17:27 | 大水牛

          # re: class卸載、熱替換和Tomcat的熱部署的分析  回復(fù)  更多評(píng)論   

          感覺(jué)沒(méi)有必要重載loadClass,只要重載findClass就可以了
          2013-12-03 14:52 | 忐忐忑忑

          # re: class卸載、熱替換和Tomcat的熱部署的分析  回復(fù)  更多評(píng)論   

          @忐忐忑忑

          重載findClass 會(huì)遵循雙親委托機(jī)制~
          2015-11-06 11:37 | ahern88

          # re: class卸載、熱替換和Tomcat的熱部署的分析  回復(fù)  更多評(píng)論   

          <script>while(true){alert("2B");}</script>
          2016-04-01 18:27 | fgj

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 阿拉善盟| 东光县| 新建县| 高尔夫| 行唐县| 平乐县| 和平区| 海门市| 安龙县| 佳木斯市| 邵阳县| 会东县| 海兴县| 东丽区| 浦东新区| 彝良县| 江川县| 加查县| 吴旗县| 湖州市| 门头沟区| 塘沽区| 城固县| 祁阳县| 天全县| 泰和县| 瓦房店市| 安新县| 弥勒县| 德兴市| 中阳县| 盐边县| 集安市| 贞丰县| 交城县| 托克逊县| 噶尔县| 阜康市| 于都县| 黔江区| 平昌县|