免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Classloader總結(jié)

顧名思義, ClassLoader就是類加載器, 而類加載是java程序運(yùn)行的第一步, 如果沒有類加載器來加載類,那么再牛逼的java程序也運(yùn)行不了, 可見類加載器的重要性。理解類加載器的加載機(jī)制, 可以很好的幫助我們理解java類的執(zhí)行過程, 深入理解java的原理, 幫助我們寫出更有效、更高效、更牛逼的程序。

委托機(jī)制

java的類加載器采用向上委托機(jī)制,需要加載一個(gè)類的時(shí)候,它的過程如下:

1. 先提交給父加載器去尋找這個(gè)類,父加載器再交給它的父加載器, 一直到最頂層的加載器BootstrapClassloader。

2. 如果BootstrapClassloader加載器找到, 那么就直接將加載后的代碼交給發(fā)起加載過程的加載器去調(diào)用, 如果沒找到,就交給BootstrapClassloader他的子加載器,也就是ExtClassloader去加載。

3. ExtClassloader如果加載成功, 就把加載后的代碼交給發(fā)起加載過程的加載器去調(diào)用, 如果沒找到,就交給ExtClassloader他的子加載器,也就是AppClassloader去加載。

4. AppClassloader重復(fù)BootstrapClassloader、ExtClassloader類似的過程, 直到加載類成功, 或者找不到目標(biāo)類, 拋出ClassNotFoundException。

整個(gè)過程如下圖所示:

其中BootstrapClassloader是JVM提供的初始化類加載器, 它是所有類加載器的根, 隨著jvm啟動(dòng)而啟動(dòng)。

加載目錄

如上圖中, 我們看到每個(gè)加載器加載類的目錄都是指定好的, 這個(gè)指定好的目錄是怎么來的呢? 這里提供一段代碼, 大家可以看輸出結(jié)果和上圖中的比較。

@SuppressWarnings("restriction")    public static void showClassLoaderPath() {        System.out.println("BootstrapClassLoader: ");        URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();        for(URL url : urls){            System.out.println(url.getPath());        }        System.out.println("BootstrapClassloader的加載目錄: " + System.getProperty("sun.boot.class.path"));        System.out.println("----------------------------");        URLClassLoader extClassLoader = (URLClassLoader)ClassLoader.getSystemClassLoader().getParent();         System.out.println(extClassLoader.getClass().getName() + ": ");          urls = extClassLoader.getURLs();        for(URL url : urls) {            System.out.println(url);          }        System.out.println("ExtClassloader的加載目錄: " + System.getProperty("java.ext.dirs"));        System.out.println("----------------------------");          URLClassLoader appClassLoader = (URLClassLoader)ClassLoader.getSystemClassLoader();        System.out.println(appClassLoader.getClass().getName() + ": ");          urls = appClassLoader.getURLs();        for(URL url : urls) {            System.out.println(url);          }        System.out.println("AppClassloader的加載目錄: " + System.getProperty("java.class.path"));    }

輸出結(jié)果如下:

BootstrapClassLoader: /D:/server/java/jdk1.6.0_10/jre/lib/resources.jar/D:/server/java/jdk1.6.0_10/jre/lib/rt.jar/D:/server/java/jdk1.6.0_10/jre/lib/sunrsasign.jar/D:/server/java/jdk1.6.0_10/jre/lib/jsse.jar/D:/server/java/jdk1.6.0_10/jre/lib/jce.jar/D:/server/java/jdk1.6.0_10/jre/lib/charsets.jar/D:/server/java/jdk1.6.0_10/jre/classesBootstrapClassloader的加載目錄: D:\server\java\jdk1.6.0_10\jre\lib\resources.jar;D:\server\java\jdk1.6.0_10\jre\lib\rt.jar;D:\server\java\jdk1.6.0_10\jre\lib\sunrsasign.jar;D:\server\java\jdk1.6.0_10\jre\lib\jsse.jar;D:\server\java\jdk1.6.0_10\jre\lib\jce.jar;D:\server\java\jdk1.6.0_10\jre\lib\charsets.jar;D:\server\java\jdk1.6.0_10\jre\classes----------------------------sun.misc.Launcher$ExtClassLoader: file:/D:/server/java/jdk1.6.0_10/jre/lib/ext/dnsns.jarfile:/D:/server/java/jdk1.6.0_10/jre/lib/ext/localedata.jarfile:/D:/server/java/jdk1.6.0_10/jre/lib/ext/sunjce_provider.jarfile:/D:/server/java/jdk1.6.0_10/jre/lib/ext/sunmscapi.jarfile:/D:/server/java/jdk1.6.0_10/jre/lib/ext/sunpkcs11.jarExtClassloader的加載目錄: D:\server\java\jdk1.6.0_10\jre\lib\ext;C:\WINDOWS\Sun\Java\lib\ext----------------------------sun.misc.Launcher$AppClassLoader: file:/D:/workspace/98_myproject/jtest/target/classes/file:/C:/Users/lenovo/.m2/repository/aopalliance/aopalliance/1.0/aopalliance-1.0.jarfile:/C:/Users/lenovo/.m2/repository/ch/qos/logback/logback-classic/1.1.2/logback-classic-1.1.2.jarfile:/C:/Users/lenovo/.m2/repository/org/slf4j/slf4j-api/1.7.6/slf4j-api-1.7.6.jarfile:/C:/Users/lenovo/.m2/repository/ch/qos/logback/logback-core/1.1.2/logback-core-1.1.2.jarfile:/C:/Users/lenovo/.m2/repository/commons-codec/commons-codec/1.9/commons-codec-1.9.jarfile:/C:/Users/lenovo/.m2/repository/commons-lang/commons-lang/2.6/commons-lang-2.6.jarfile:/C:/Users/lenovo/.m2/repository/commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.jarfile:/C:/Users/lenovo/.m2/repository/commons-configuration/commons-configuration/1.10/commons-configuration-1.10.jarfile:/C:/Users/lenovo/.m2/repository/org/apache/httpcomponents/fluent-hc/4.3.3/fluent-hc-4.3.3.jarfile:/C:/Users/lenovo/.m2/repository/org/apache/httpcomponents/httpclient/4.3.3/httpclient-4.3.3.jarfile:/C:/Users/lenovo/.m2/repository/org/apache/httpcomponents/httpcore/4.3.2/httpcore-4.3.2.jarfile:/C:/Users/lenovo/.m2/repository/org/apache/httpcomponents/httpclient-cache/4.3.3/httpclient-cache-4.3.3.jarfile:/C:/Users/lenovo/.m2/repository/org/apache/httpcomponents/httpmime/4.3.3/httpmime-4.3.3.jarfile:/C:/Users/lenovo/.m2/repository/org/quartz-scheduler/quartz/2.2.1/quartz-2.2.1.jarfile:/C:/Users/lenovo/.m2/repository/postgresql/postgresql/9.1-901-1.jdbc4/postgresql-9.1-901-1.jdbc4.jarfile:/C:/Users/lenovo/.m2/repository/commons-dbutils/commons-dbutils/1.5/commons-dbutils-1.5.jarfile:/C:/Users/lenovo/.m2/repository/c3p0/c3p0/0.9.1.2/c3p0-0.9.1.2.jarfile:/C:/Users/lenovo/.m2/repository/junit/junit/4.12-beta-2/junit-4.12-beta-2.jarfile:/C:/Users/lenovo/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jarAppClassloader的加載目錄: D:\workspace\98_myproject\jtest\target\classes;C:\Users\lenovo\.m2\repository\aopalliance\aopalliance\1.0\aopalliance-1.0.jar;C:\Users\lenovo\.m2\repository\ch\qos\logback\logback-classic\1.1.2\logback-classic-1.1.2.jar;C:\Users\lenovo\.m2\repository\org\slf4j\slf4j-api\1.7.6\slf4j-api-1.7.6.jar;C:\Users\lenovo\.m2\repository\ch\qos\logback\logback-core\1.1.2\logback-core-1.1.2.jar;C:\Users\lenovo\.m2\repository\commons-codec\commons-codec\1.9\commons-codec-1.9.jar;C:\Users\lenovo\.m2\repository\commons-lang\commons-lang\2.6\commons-lang-2.6.jar;C:\Users\lenovo\.m2\repository\commons-logging\commons-logging\1.1.3\commons-logging-1.1.3.jar;C:\Users\lenovo\.m2\repository\commons-configuration\commons-configuration\1.10\commons-configuration-1.10.jar;C:\Users\lenovo\.m2\repository\org\apache\httpcomponents\fluent-hc\4.3.3\fluent-hc-4.3.3.jar;C:\Users\lenovo\.m2\repository\org\apache\httpcomponents\httpclient\4.3.3\httpclient-4.3.3.jar;C:\Users\lenovo\.m2\repository\org\apache\httpcomponents\httpcore\4.3.2\httpcore-4.3.2.jar;C:\Users\lenovo\.m2\repository\org\apache\httpcomponents\httpclient-cache\4.3.3\httpclient-cache-4.3.3.jar;C:\Users\lenovo\.m2\repository\org\apache\httpcomponents\httpmime\4.3.3\httpmime-4.3.3.jar;C:\Users\lenovo\.m2\repository\org\quartz-scheduler\quartz\2.2.1\quartz-2.2.1.jar;C:\Users\lenovo\.m2\repository\postgresql\postgresql\9.1-901-1.jdbc4\postgresql-9.1-901-1.jdbc4.jar;C:\Users\lenovo\.m2\repository\commons-dbutils\commons-dbutils\1.5\commons-dbutils-1.5.jar;C:\Users\lenovo\.m2\repository\c3p0\c3p0\0.9.1.2\c3p0-0.9.1.2.jar;C:\Users\lenovo\.m2\repository\junit\junit\4.12-beta-2\junit-4.12-beta-2.jar;C:\Users\lenovo\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar

可以看到和圖中所示的各個(gè)類加載器加載范圍是一致的, 同時(shí)我們也可以看到, jvm提供的加載器所加載的目錄所對(duì)應(yīng)的系統(tǒng)屬性值。

依賴順序

那么問題來了。 假如我們的項(xiàng)目有個(gè)依賴包A被放到了jre/lib/ext目錄下, 而這個(gè)依賴包依賴的另一個(gè)依賴包B放在項(xiàng)目目錄, 這個(gè)時(shí)候我們可以加在成功嗎?

答案是不可以的。

因?yàn)閖ava的類加載機(jī)制是向上委托, 而不是向下委托, 也就是說ExtClassloader可以調(diào)用BootstrapClassLoader加載的類, AppClassLoader可以調(diào)用ExtClassloader和BootstrapClassLoader加載的類, 而這個(gè)過程反過來是不行的。

在我們的這個(gè)問題中, 依賴包A被ExtClassloader加載, B被AppClassloader加載, 這個(gè)時(shí)候A要引用B包中的類, 按照我們上面講的機(jī)制是不可以的。 當(dāng)然它并不是絕對(duì)的, java提供了一種繞開上述機(jī)制的方法, 下面我們會(huì)講到。

反向依賴

那么怎么可以突破向上委托這種機(jī)制呢?

JDK 1.2提供了一個(gè)叫線程上下文類加載器, 對(duì)應(yīng)代碼就是java.lang.Thread中的方法getContextClassLoader()和setContextClassLoader(ClassLoader cl)用來獲取和設(shè)置線程的上下文類加載器。如果沒有通過setContextClassLoader(ClassLoader cl)方法進(jìn)行設(shè)置的話,線程將繼承其父線程的上下文類加載器。Java 應(yīng)用運(yùn)行的初始線程的上下文類加載器是系統(tǒng)類加載器。

那么什么情況下以上類加載機(jī)制會(huì)失效呢?

Java 提供了很多服務(wù)提供者接口(Service Provider Interface,SPI),允許第三方為這些接口提供實(shí)現(xiàn)。 常見的 SPI 有 JDBC、JCE、JNDI、JAXP 和 JBI 等。這些 SPI 的接口由 Java 核心庫來提供,如 JAXP 的 SPI 接口定義包含在 javax.xml.parsers包中。這些 SPI 的實(shí)現(xiàn)代碼很可能是作為 Java 應(yīng)用所依賴的 jar 包被包含進(jìn)來,可以通過類路徑(CLASSPATH)來找到,如實(shí)現(xiàn)了 JAXP SPI 的 Apache Xerces所包含的 jar 包。SPI 接口中的代碼經(jīng)常需要加載具體的實(shí)現(xiàn)類。如 JAXP 中的 javax.xml.parsers.DocumentBuilderFactory類中的 newInstance()方法用來生成一個(gè)新的 DocumentBuilderFactory的實(shí)例。這里的實(shí)例的真正的類是繼承自 javax.xml.parsers.DocumentBuilderFactory,由 SPI 的實(shí)現(xiàn)所提供的。如在 Apache Xerces 中,實(shí)現(xiàn)的類是 org.apache.xerces.jaxp.DocumentBuilderFactoryImpl。而問題在于,SPI 的接口是 Java 核心庫的一部分,是由引導(dǎo)類加載器來加載的;SPI 實(shí)現(xiàn)的 Java 類一般是由系統(tǒng)類加載器來加載的。引導(dǎo)類加載器是無法找到 SPI 的實(shí)現(xiàn)類的,因?yàn)樗患虞d Java 的核心庫。它也不能代理給系統(tǒng)類加載器,因?yàn)樗窍到y(tǒng)類加載器的祖先類加載器。也就是說,類加載器的代理模式無法解決這個(gè)問題。 引用自: http://www.ibm.com/developerworks/cn/java/j-lo-classloader/
線程上下文類加載器正好解決了這個(gè)問題。如果不做任何的設(shè)置,Java 應(yīng)用的線程的上下文類加載器默認(rèn)就是系統(tǒng)上下文類加載器。在 SPI 接口的代碼中使用線程上下文類加載器,就可以成功的加載到 SPI 實(shí)現(xiàn)的類。線程上下文類加載器在很多 SPI 的實(shí)現(xiàn)中都會(huì)用到。

自定義類加載器

大多數(shù)情況下jdk提供的類加載器已經(jīng)足夠我們使用, 但是在某些特殊情況下, 需要我們編寫自定義的類加載器來實(shí)現(xiàn)特定功能, 如OSGI框架。如我們?cè)诰W(wǎng)絡(luò)上傳輸類文件的時(shí)候?qū)Ψ郊用芰耍?我們就要編寫對(duì)應(yīng)解密的類加載器來加載對(duì)方發(fā)過來的類。

自定義類加載器主要需要注意的就是繼承ClassLoader, 并實(shí)現(xiàn)其中的findClass方法, 如下:

public class MyClassLoader extends ClassLoader{    @Override	protected Class<?> findClass(String name) throws ClassNotFoundException {}}
這里再引用網(wǎng)絡(luò)上其他人寫好的一個(gè)類加載器示例來幫助大家更好的掌握自定義類加載器。
public class FileSystemClassLoader extends ClassLoader {     private String rootDir;     public FileSystemClassLoader(String rootDir) {         this.rootDir = rootDir;     }     protected Class<?> findClass(String name) throws ClassNotFoundException {         byte[] classData = getClassData(name);         if (classData == null) {             throw new ClassNotFoundException();         }         else {             return defineClass(name, classData, 0, classData.length);         }     }     private byte[] getClassData(String className) {         String path = classNameToPath(className);         try {             InputStream ins = new FileInputStream(path);             ByteArrayOutputStream baos = new ByteArrayOutputStream();             int bufferSize = 4096;             byte[] buffer = new byte[bufferSize];             int bytesNumRead = 0;             while ((bytesNumRead = ins.read(buffer)) != -1) {                 baos.write(buffer, 0, bytesNumRead);             }             return baos.toByteArray();         } catch (IOException e) {             e.printStackTrace();         }         return null;     }     private String classNameToPath(String className) {         return rootDir + File.separatorChar                 + className.replace('.', File.separatorChar) + ".class";     }  }
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
java基礎(chǔ):Q8. 類加載器的相關(guān)知識(shí)
類加載器機(jī)器委托機(jī)制的深入
classLoader動(dòng)態(tài)加載
java Class類
Java高級(jí)篇——深入淺出Java類加載機(jī)制
Java類加載機(jī)制
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服