摘要:標(biāo)準(zhǔn)擴(kuò)展類加載器,它負(fù)責(zé)加載或由系統(tǒng)變量指定位置中的類庫加載到內(nèi)存中。系統(tǒng)類加載器,它負(fù)責(zé)將類路徑中的類庫加載到內(nèi)存。
類加載機(jī)制大家應(yīng)該已經(jīng)非常熟悉了,采取雙親委派機(jī)制,當(dāng)加載一個(gè)類時(shí),首先將加載任務(wù)委托給父類加載器,依次遞歸,如果父類加載器可以完成加載任務(wù),就成功返回;如果父類無法加載,才由自己加載。
雙親委派機(jī)制的作用:防止內(nèi)存中出現(xiàn)多份相同的字節(jié)碼。
其他規(guī)則:
1.隱式加載:在當(dāng)前類中所有new的對(duì)象,如果沒有被加載,則使用當(dāng)前類的類加載器加載 如果類A中引用了類B,Java虛擬機(jī)將使用加載類A的類加載器去加載類B
2.不同類加載器加載的類是不同的,通過類加載器+類全路徑來唯一標(biāo)識(shí)一個(gè)類
JVM預(yù)定義的三種類加載器:
1.Bootstrap ClassLoader:啟動(dòng)類加載器,它負(fù)責(zé)將JAVA_HOME/lib下面的類庫加載到內(nèi)存中,如rt.jar;啟動(dòng)類加載器是由C++寫的二進(jìn)制代碼,不是java類,在JVM啟動(dòng)的時(shí)候Bootstrap就已經(jīng)啟動(dòng)。
2.Extension ClassLoader:標(biāo)準(zhǔn)擴(kuò)展類加載器,它負(fù)責(zé)加載JAVA_HOME/lib/ext或由系統(tǒng)變量java.ext.dir指定位置中的類庫加載到內(nèi)存中。
3.APP ClassLoader:系統(tǒng)類加載器(System ClassLoader),它負(fù)責(zé)將類路徑CLASSPATH中的類庫加載到內(nèi)存。
加載順序圖如下:
圖中的BootStrapClassLoader、ExtClassLoader、APPClassLoader不是真正的繼承關(guān)系,只是邏輯上的上下級(jí)類加載器;
實(shí)際上的類關(guān)系如下圖:
可以看到ExtClassLoader和APPCLassLoader都繼承自URLClassLoader,也就證實(shí)了二者并非真正的繼承關(guān)系;
通過上圖可以看到最頂層的類是抽象類ClassLoader:是所有類加載器的基類(除了啟動(dòng)類加載器),定義了類加載最核心的操作;
SecureClassLoader:添加了關(guān)聯(lián)類源碼、關(guān)聯(lián)系統(tǒng)權(quán)限支持
URLClassLoader:支持從jar文件和文件夾中獲取class
ExtClassLoader:擴(kuò)展類加載器Extension ClassLoader
APPClassLoader:系統(tǒng)類加載器,也稱為System ClassLoader
ClassLoader:
父子類加載器是通過ClassLoader一個(gè)parent屬性來標(biāo)識(shí),APPClassLoader的父加載器是ExtClassLoader,ExtClassLoader的父加載器是null。
ClassLoader提供了兩個(gè)構(gòu)造器,一個(gè)是沒有參數(shù)的,一個(gè)是有參數(shù)的;如下圖:
沒有參數(shù)的構(gòu)造器默認(rèn)將系統(tǒng)類加載器作為parent加載器;
有參數(shù)的構(gòu)造器將參數(shù)指定的加載器作為父類加載器;
Launcher:
ExtClassLoader和AppClassLoader都是Launcher的子類,在ClassLoader初始化或者直接通過ClassLoader的getSystemClassLoader()獲取的時(shí)候會(huì)調(diào)用initSystemClassLoader(),從而調(diào)用sun.misc.Launcher.getLauncher(),將系統(tǒng)類加載器賦值給ClassLoader的scl變量;
我們看下Launcher類初始化的時(shí)候都做了什么工作,如圖:
主要是三部工作:
1.創(chuàng)建ExtClassLoader
2.創(chuàng)建AppClassLoader
3.將線程系統(tǒng)類加載器設(shè)置為線程上下文類加載器,什么是上線文類加載器?
線程上下文類加載器:
java提供了為很多服務(wù)商提供了接口,簡稱SPI(Service Provider Interface),具體的實(shí)現(xiàn)由各廠商提供,例如mysql驅(qū)動(dòng),oracle驅(qū)動(dòng)等。例如:mysql驅(qū)動(dòng)加載接口類在rt.jar中,由啟動(dòng)類加載器加載,具體實(shí)現(xiàn)類在mysql驅(qū)動(dòng)包中,驅(qū)動(dòng)包一般放到我們自己的程序路徑lib下,應(yīng)該由系統(tǒng)類加載器加載;但是在使用如下代碼進(jìn)行數(shù)據(jù)庫連接使用操作的時(shí)候,就會(huì)出現(xiàn)在rt.jar中要加載驅(qū)動(dòng)包里代碼的情況(類加載器是啟動(dòng)類加載器),由隱式加載規(guī)則可知,驅(qū)動(dòng)包也要使用啟動(dòng)類加載器加載,由類加載機(jī)制可知,是無法通過啟動(dòng)類加載器來加載的;那這種情況怎么辦呢,就要通過線程上下文類加載器來解決。
上面描述的情況如下:使用jdbc進(jìn)行數(shù)據(jù)庫操作如下
1.Class.forName("com.mysql.jdbc.Driver");// 加載mysql驅(qū)動(dòng) 2.Connection conn = DriverManager.getConnection(url);//創(chuàng)建連接 3.Statement stmt = conn.createStatement();//得到statement對(duì)象 4.操作數(shù)據(jù)庫 關(guān)閉連接。。
第一步在實(shí)例化Driver時(shí),會(huì)調(diào)用DriverManager的registerDriver()方法收集divers,將驅(qū)動(dòng)類注冊(cè)到DriverManager容器中,DriverManage的drivers容器:
注冊(cè)的代碼:
Class.forName("com.mysql.jdbc.Driver")相當(dāng)于:
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class driversClass = loader.loadClass("com.mysql.jdbc.Driver");
driversClass.newInstance();
由此可見com.mysql.jdbc.Driver是由我們自己應(yīng)用類加載器AppClassLoader進(jìn)行加載;
第二步通過DriverManager.getConnection(url),會(huì)循環(huán)獲取drivers中的driver,調(diào)用具體driver實(shí)現(xiàn)里的cnnect()方法,進(jìn)行連接
caller.getClassLoader()是啟動(dòng)類加載器為null,因此callerCL為系統(tǒng)類加載器
getConnection通過isDriverAllowed方法校驗(yàn)類是否有權(quán)限被加載
通過AppClassLoader來加載Driver看是否和已注冊(cè)的Driver是同一個(gè)類,如果是則調(diào)用driver的connect方法
在java6以后,引入了service provider概念,在/META-INF/services/java.sql.Driver文件中配置需要加載的驅(qū)動(dòng)類,
在DriverManager初始化的時(shí)候會(huì)調(diào)用loadInitialDrivers方法,
會(huì)使用AppClassLoader進(jìn)行加載,所以在自己程序中可以不用Class.forName顯示調(diào)用。
上面包類結(jié)構(gòu)如下圖:
tomcat類加載
我們運(yùn)行tomcat的多個(gè)實(shí)例,不想安裝tomcat軟件副本,我們可以配置多個(gè)工作目錄,每個(gè)運(yùn)行實(shí)例獨(dú)占一個(gè)工作目錄,但是共享一個(gè)安裝目錄。
變量解釋:
CATALINA_HOME:tomcat安裝目錄,多個(gè)工作目錄可共享安裝目錄
CATALINA_BASE:tomcat工作目錄,tomcat每個(gè)運(yùn)行實(shí)例需要使用自己的conf、logs、temp、webapps、work、shared目錄,CATALINA_BASE就是指向這個(gè)目錄
如下圖:兩個(gè)應(yīng)用公用CATALINA_HOME,CATALINA_BASE指向各自工作目錄
首先看下tomcat在啟動(dòng)時(shí)類初始化類加載器過程
首先是創(chuàng)建commonClassLoader,commonClassLoader加載的是配置文件catalina.properties中配置的
common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar
server.loader=
shared.loader=
例如在我們的服務(wù)器上路徑是:
/opt/soft/tomcat/lib、/opt/soft/tomcat/lib/*.jar
因?yàn)閟erver.loader和shared.loader未配置具體加載目錄信息,catalinaLoader和sharedLoader默認(rèn)為commonLoader(在tomcat5以后catalinaLoader和sharedLoader默認(rèn)不啟用)
tomcat一共定義了兩種類加載器
StandardClassLoader:實(shí)例化commonloader、catalinaLoader、sharedLoader,不提供熱部署功能,遵循雙親委派機(jī)制
WebappClassLoader:和context級(jí)容器相關(guān)聯(lián),加載web程序,支持其加載路徑下資源改變后重新加載,不遵循雙親委派機(jī)制。
其類繼承關(guān)系如下:
除此之外還有兩個(gè)類:WebappLoader和VirtualWebappLoader,該兩個(gè)類不是類加載器,只是對(duì)WebappClassLoader做了封裝,對(duì)熱部署、生命周期控制等功能做了一些控制;
VirtualWebappLoader是WebappLoader的子類,主要是和conf/context.xml這個(gè)文件相關(guān)聯(lián),主要功能是加載context.xml配置文件中設(shè)置的一些java類庫,由于WebappClassLoader只能加載WEB-INF/class和WEB-INF/lib下的類庫。而想擴(kuò)展一下加載路徑又不想添加到WEB-INF/lib中的時(shí)候,可以配置在context.xml文件中。
自己實(shí)現(xiàn)類記載器只要實(shí)現(xiàn)findclass即可,這里為了實(shí)現(xiàn)特殊目的而override了loadClass();WebappClassLoader重寫了loadClass方法,先自己加載,如果加載不了再進(jìn)行其他操作。
所以在Tomcat 6中默認(rèn)情況下,不是完全按照先Tomcat的lib再Web應(yīng)用的lib這種順序去加載類。
Jar包的加載順序是:
1)JRE中的Java基礎(chǔ)包
2)Web應(yīng)用WEB-INF/lib下的包
3)Tomcat/lib下的包
如果想要在Web應(yīng)用間共享一些Jar包,則不僅需要將公共包放在Tomcat的lib下,還要?jiǎng)h掉Web應(yīng)用lib中的包,否則Tomcat啟動(dòng)時(shí)還是會(huì)優(yōu)先加載Web應(yīng)用lib下的包的。
如果想要自己指定一個(gè)Tomcatlib和Web應(yīng)用lib之外的ClassPath,除了修改Tomcat啟動(dòng)腳本外,可以為不同Web應(yīng)用的Context指定一個(gè)VirtualWebappLoader,但源碼注釋中寫到不推薦在生產(chǎn)環(huán)境中使用。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/70300.html
摘要:程序計(jì)數(shù)器程序計(jì)數(shù)器是一塊較小的內(nèi)存空間,它的作用可以看做是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器。它的主要缺點(diǎn)有兩個(gè)一個(gè)是效率問題,標(biāo)記和清除過程的效率都不 Jvm 相關(guān) 類加載機(jī)制 本段參考 http://www.importnew.com/2374... 類加載概念 類加載指的是將類的.class文件中的二進(jìn)制數(shù)據(jù)讀入到內(nèi)存中,將其放在運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)內(nèi),然后在堆區(qū)創(chuàng)建一個(gè)ja...
摘要:驗(yàn)證過程驗(yàn)證過程的目的是為了確保文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,并且不會(huì)危害虛擬機(jī)自身的安全。二虛擬機(jī)字節(jié)碼執(zhí)行引擎虛擬機(jī)的執(zhí)行引擎自行實(shí)現(xiàn),可以自行制定指令集與執(zhí)行引擎的結(jié)構(gòu)體系。 本篇博客主要針對(duì)Java虛擬機(jī)的類加載機(jī)制,虛擬機(jī)字節(jié)碼執(zhí)行引擎,早期編譯優(yōu)化進(jìn)行總結(jié),其余部分總結(jié)請(qǐng)點(diǎn)擊Java虛擬總結(jié)上篇 。 一.虛擬機(jī)類加載機(jī)制 概述 虛擬機(jī)把描述類的數(shù)據(jù)從Clas...
摘要:典型應(yīng)用鎖和同步器框架的核心類,就是通過調(diào)用和實(shí)現(xiàn)線程的阻塞和喚醒的,而的方法實(shí)際是調(diào)用的方式來實(shí)現(xiàn)。 前言 Unsafe是位于sun.misc包下的一個(gè)類,主要提供一些用于執(zhí)行低級(jí)別、不安全操作的方法,如直接訪問系統(tǒng)內(nèi)存資源、自主管理內(nèi)存資源等,這些方法在提升Java運(yùn)行效率、增強(qiáng)Java語言底層資源操作能力方面起到了很大的作用。但由于Unsafe類使Java語言擁有了類似C語言指針...
摘要:二驗(yàn)證驗(yàn)證主要是為了確保文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,并且不會(huì)危害虛擬機(jī)的自身安全。五初始化類的初始化階段是類加載過程的最后一步,該階段才真正開始執(zhí)行類中定義的程序代碼或者說是字節(jié)碼。 關(guān)注我,每天三分鐘,帶你輕松掌握一個(gè)Java相關(guān)知識(shí)點(diǎn)。 虛擬機(jī)(JVM)經(jīng)常出現(xiàn)在我們面試中,但是工作中卻很少遇到,導(dǎo)致很多同學(xué)沒有去了解過。其實(shí)除了應(yīng)付面試,作為java程序員,了解...
閱讀 2224·2021-11-23 09:51
閱讀 2940·2021-11-22 15:35
閱讀 3040·2019-08-30 15:53
閱讀 1116·2019-08-30 14:04
閱讀 3352·2019-08-29 12:39
閱讀 1909·2019-08-28 17:57
閱讀 1212·2019-08-26 13:39
閱讀 638·2019-08-26 13:34