JavaJVM之ClassLoader源码分析
層次結(jié)構(gòu)和類圖
ClassLoader層次結(jié)構(gòu):? UML類圖:
?
- sun.misc.Launcher.ExtClassLoader
- sun.misc.Launcher.AppClassLoader
顯式加載類
在代碼中顯式加載某個(gè)類,有三種方法: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()的最后一步是調(diào)用findClass(),這個(gè)方法在ClassLoader中并未實(shí)現(xiàn),由其子類負(fù)責(zé)實(shí)現(xiàn)。
findClass()的功能是找到class文件并把字節(jié)碼加載到內(nèi)存中。
自定義的ClassLoader一般覆蓋這個(gè)方法。——以便使用不同的加載路徑。
? ??? /*?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文件字節(jié)流 ????????????//??? URLClassPath會(huì)用FileLoader或者JarLoader去加載字節(jié)碼? ????????????Resource?res?=?ucp.getResource(path,?false);? ????????????if?(res?!=?null)?{ ????????????????try?{ ??????????????? // 2. defineClass,創(chuàng)建類對(duì)象,將字節(jié)流解析成JVM能夠識(shí)別的Class對(duì)象。 ????????????????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()
加載完字節(jié)碼后,會(huì)根據(jù)需要進(jìn)行驗(yàn)證、解析。 ????/** ?????*?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文件并把字節(jié)碼加載到內(nèi)存中。
自定義的ClassLoader一般覆蓋這個(gè)方法。——以便使用不同的加載路徑。
在其中調(diào)用defineClass()解析字節(jié)碼。
-
loadClass()定義加載機(jī)制
自定義的加載器可以覆蓋該方法loadClass(),以便定義不同的加載機(jī)制。
例如Servlet中的WebappClassLoader覆蓋了該方法,在WEB-INFO/classes目錄下查找類文件;在加載時(shí),如果成功,則緩存到ResourceEntry對(duì)象。——不同的加載機(jī)制。
?
AppClassLoader覆蓋了loadClass()方法。
如果自定義的加載器僅覆蓋了findClass,而未覆蓋loadClass(即加載規(guī)則一樣,但加載路徑不同);則調(diào)用getClass().getClassLoader()返回的仍然是AppClassLoader!因?yàn)檎嬲齦oad類的,還是AppClassLoader。
-
實(shí)現(xiàn)類的熱部署
JVM默認(rèn)不能熱部署類,因?yàn)榧虞d類時(shí)會(huì)去調(diào)用findLoadedClass(),如果類已被加載,就不會(huì)再次加載。
JVM判斷類是否被加載有兩個(gè)條件:完整類名是否一樣、ClassLoader是否是同一個(gè)。
所以要實(shí)現(xiàn)熱部署的話,只需要使用ClassLoader的不同實(shí)例來(lái)加載。
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就是兩個(gè)不同的實(shí)例。
如果用同一個(gè)ClassLoader實(shí)例來(lái)加載,則會(huì)拋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)總結(jié)
以上是生活随笔為你收集整理的JavaJVM之ClassLoader源码分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Android插件化开发基础之Java类
- 下一篇: Android插件化开发之动态加载基础之