JavaJVM之ClassLoader源码分析
層次結構和類圖
ClassLoader層次結構:? UML類圖:
?
- sun.misc.Launcher.ExtClassLoader
- sun.misc.Launcher.AppClassLoader
顯式加載類
在代碼中顯式加載某個類,有三種方法:ClassLoader.loadClass()
ClassLoader.loadClass()的加載步驟為:?
????public?Class<?>?loadClass(String?name)?throws?ClassNotFoundException?{ ???????return?loadClass(name,?false); ????} ????/** ?????*?Loads?the?class?with?the?specified?<a?href="#name">binary?name</a>.??The ?????*?default?implementation?of?this?method?searches?for?classes?in?the ?????*?following?order: ?????* ?????*?<p><ol> ?????* ?????*???<li><p>?Invoke?{@link?#findLoadedClass(String)}?to?check?if?the?class ?????*???has?already?been?loaded.??</p></li> ?????* ?????*???<li><p>?Invoke?the?{@link?#loadClass(String)?<tt>loadClass</tt>}?method ?????*???on?the?parent?class?loader.??If?the?parent?is?<tt>null</tt>?the?class ?????*???loader?built-in?to?the?virtual?machine?is?used,?instead.??</p></li> ?????* ?????*???<li><p>?Invoke?the?{@link?#findClass(String)}?method?to?find?the ?????*???class.??</p></li> ?????* ?????*?</ol> ?????* ?????*?<p>? ?????*/ ????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?=?findBootstrapClassOrNull(name); ????????} ????????}?catch?(ClassNotFoundException?e)?{ ????????????????//?ClassNotFoundException?thrown?if?class?not?found ????????????????//?from?the?non-null?parent?class?loader ????????????} ????????????if?(c?==?null)?{ ????????????//?If?still?not?found,?then?invoke?findClass?in?order ????????????//?to?find?the?class. ????????????c?=?findClass(name); ????????} ????} ????if?(resolve)?{ ????????resolveClass(c); ????} ????return?c; ????}URLClassLoader.findClass()
ClassLoader.loadClass()的最后一步是調用findClass(),這個方法在ClassLoader中并未實現,由其子類負責實現。
findClass()的功能是找到class文件并把字節碼加載到內存中。
自定義的ClassLoader一般覆蓋這個方法。——以便使用不同的加載路徑。
? ??? /*?The?search?path?for?classes?and?resources?*/ ????URLClassPath?ucp; ????/*?The?context?to?be?used?when?loading?classes?and?resources?*/ ????private?AccessControlContext?acc; /** ?????*?Finds?and?loads?the?class?with?the?specified?name?from?the?URL?search ?????*?path.?Any?URLs?referring?to?JAR?files?are?loaded?and?opened?as?needed ?????*?until?the?class?is?found. ?????* ?????*?@param?name?the?name?of?the?class ?????*?@return?the?resulting?class ?????*?@exception?ClassNotFoundException?if?the?class?could?not?be?found ?????*/ ????protected?Class<?>?findClass(final?String?name) ?????throws?ClassNotFoundException ????{ ????try?{ ????????return?(Class) ????????AccessController.doPrivileged(new?PrivilegedExceptionAction()?{ ????????????public?Object?run()?throws?ClassNotFoundException?{ ????????????String?path?=?name.replace('.',?'/').concat(".class"); ??????????? // 1. URLClassPath ucp,幫助獲取class文件字節流 ????????????//??? URLClassPath會用FileLoader或者JarLoader去加載字節碼? ????????????Resource?res?=?ucp.getResource(path,?false);? ????????????if?(res?!=?null)?{ ????????????????try?{ ??????????????? // 2. defineClass,創建類對象,將字節流解析成JVM能夠識別的Class對象。 ????????????????return?defineClass(name,?res,?true); ????????????????}?catch?(IOException?e)?{ ????????????????throw?new?ClassNotFoundException(name,?e); ????????????????} ????????????}?else?{ ????????????????throw?new?ClassNotFoundException(name); ????????????} ????????????} ????????},?acc); ????}?catch?(java.security.PrivilegedActionException?pae)?{ ????????throw?(ClassNotFoundException)?pae.getException(); ????} ????}ClassLoader.resolveClass()
加載完字節碼后,會根據需要進行驗證、解析。 ????/** ?????*?Links?the?specified?class.??This?(misleadingly?named)?method?may?be ?????*?used?by?a?class?loader?to?link?a?class.??If?the?class?<tt>c</tt>?has ?????*?already?been?linked,?then?this?method?simply?returns.?Otherwise,?the ?????*?class?is?linked?as?described?in?the?"Execution"?chapter?of?the?<a ?????*?href="http://java.sun.com/docs/books/jls/">Java?LanguageSpecification</a>. ?????*?</p> ?????* ?????*?@param??c ?????*?????????The?class?to?link ?????* ?????*?@throws??NullPointerException ?????*??????????If?<tt>c</tt>?is?<tt>null</tt>. ?????* ?????*?@see??#defineClass(String,?byte[],?int,?int) ?????*/ ????protected?final?void?resolveClass(Class<?>?c)?{ ????resolveClass0(c); ????} ????private?native?void?resolveClass0(Class?c);自定義加載器
-
findClass()定義加載路徑
findClass()的功能是找到class文件并把字節碼加載到內存中。
自定義的ClassLoader一般覆蓋這個方法。——以便使用不同的加載路徑。
在其中調用defineClass()解析字節碼。
-
loadClass()定義加載機制
自定義的加載器可以覆蓋該方法loadClass(),以便定義不同的加載機制。
例如Servlet中的WebappClassLoader覆蓋了該方法,在WEB-INFO/classes目錄下查找類文件;在加載時,如果成功,則緩存到ResourceEntry對象。——不同的加載機制。
?
AppClassLoader覆蓋了loadClass()方法。
如果自定義的加載器僅覆蓋了findClass,而未覆蓋loadClass(即加載規則一樣,但加載路徑不同);則調用getClass().getClassLoader()返回的仍然是AppClassLoader!因為真正load類的,還是AppClassLoader。
-
實現類的熱部署
JVM默認不能熱部署類,因為加載類時會去調用findLoadedClass(),如果類已被加載,就不會再次加載。
JVM判斷類是否被加載有兩個條件:完整類名是否一樣、ClassLoader是否是同一個。
所以要實現熱部署的話,只需要使用ClassLoader的不同實例來加載。
MyClassLoader cl1 = new MyClassLoader();
Class c1 = cl1.findClass("Test.class"); c1.newInstance();
MyClassLoader cl2 = new MyClassLoader();
Class c2 = cl2.findClass("Test.class"); c2.newInstance();
上例中的c1和c2就是兩個不同的實例。
如果用同一個ClassLoader實例來加載,則會拋LinkageError。
?
-
不可覆蓋的final方法
defineClass
????/** ?????*?Converts?an?array?of?bytes?into?an?instance?of?class?<tt>Class</tt>. ?????*?Before?the?<tt>Class</tt>?can?be?used?it?must?be?resolved. ?????*/ protected?final?Class<?>?defineClass(String?name,?byte[]?b,?int?off,?int?len) ?findLoadedClass
????/** ?????*?Returns?the?class?with?the?given?<a?href="#name">binary?name</a>?if?this ?????*?loader?has?been?recorded?by?the?Java?virtual?machine?as?an?initiating ?????*?loader?of?a?class?with?that?<a?href="#name">binary?name</a>.??Otherwise ?????*?<tt>null</tt>?is?returned.??</p> ?????*/ protected?final?Class<?>?findLoadedClass(String?name)? ?findSystemClass
? ????/** ?????*?Finds?a?class?with?the?specified?<a?href="#name">binary?name</a>, ?????*?loading?it?if?necessary. ?????* ?????*?<p>?This?method?loads?the?class?through?the?system?class?loader?(see ?????*?{@link?#getSystemClassLoader()}).??The?<tt>Class</tt>?object?returned ?????*?might?have?more?than?one?<tt>ClassLoader</tt>?associated?with?it. ?????*?Subclasses?of?<tt>ClassLoader</tt>?need?not?usually?invoke?this?method, ?????*?because?most?class?loaders?need?to?override?just?{@link?#findClass(String)}.??</p> ?????*/ protected?final?Class<?>?findSystemClass(String?name) ?getParent
????/** ?????*?Returns?the?parent?class?loader?for?delegation.?Some?implementations?may ?????*?use?<tt>null</tt>?to?represent?the?bootstrap?class?loader.?This?method ?????*?will?return?<tt>null</tt>?in?such?implementations?if?this?class?loader's ?????*?parent?is?the?bootstrap?class?loader. ?????*/ public?final?ClassLoader?getParent() ?resolveClass
?/** ?????*?Links?the?specified?class.??This?(misleadingly?named)?method?may?be ?????*?used?by?a?class?loader?to?link?a?class.??If?the?class?<tt>c</tt>?has ?????*?already?been?linked,?then?this?method?simply?returns.?Otherwise,?the ?????*?class?is?linked?as?described?in?the?"Execution"?chapter?of?the?<a ?????*?href="http://java.sun.com/docs/books/jls/">Java?Language?Specification</a>. ?????*/ protected?final?void?resolveClass(Class<?>?c)總結
以上是生活随笔為你收集整理的JavaJVM之ClassLoader源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android插件化开发基础之Java类
- 下一篇: C语言之strstr函数类似Java字符