1.openfire的入口main文件在src/java 文件夾下的org.jivesoftware.openfire.starter包中。 2.運(yùn)行main函數(shù)之后openfire會(huì)調(diào)用start方法,首先是獲取到ClassLoader對(duì)象。那么什么是ClassLoader對(duì)象呢? 下面具體學(xué)習(xí)ClassLoader的知識(shí)。 首先ClassLoader作用是加載Class文件到j(luò)vm中,供程序使用,java程序可以動(dòng)態(tài)加載類定義,這個(gè)動(dòng)態(tài)加載的機(jī)制就是通過ClassLoader來實(shí)現(xiàn)的。 ClassLoader 是加載Class文件的(ExtClassLoader和AppClassLoader也在此時(shí)被加載),那么ClassLoader又被誰加載呢?是一 個(gè)被不是java語言所編寫的ClassLoader來加載的,這個(gè)ClassLoader就是bootstrapClassLoader(啟動(dòng)類加載 器)。這個(gè)加載器在jvm運(yùn)行的時(shí)候加載java核心的api以滿足java程序最基本的需求。其中包括用戶定義的ClassLoader,用戶定義的 ClassLoader就是通過程序創(chuàng)建的ClassLoader,那么也有非程序員創(chuàng)建的ClassLoader,就是jvm自己提供的吧(這句是自己 理解的)。用戶自定義的ClassLoader有ExtClassLoader,ExtClassLoader加載java的擴(kuò)展的api,也就是 /lib/ext中的類。用戶自定義的ClassLoader還有AppClassLoader,AppClassLoader用戶機(jī)器上的 CLASSPATH設(shè)置目錄中的Class的,通常在沒有指定ClassLoader的情況下,程序自定義的類由AppClassLoader加載 ClassLoader 的加載模式:雙親委托模式進(jìn)行加載。該模式的原理是:某個(gè)自定義的ClassLoader加載Class的時(shí)候都會(huì)先委托他的parnet ClassLoader加載該Class,當(dāng)parent ClassLoader加載失敗,再由當(dāng)前的ClassLoader加載該Class,但是如果該ClassLoader的parent ClassLoader為null那么該ClassLoader的parent就是bootstrapClassLoader。 使用雙親委托模式的優(yōu)點(diǎn)是: 第一:避免重復(fù)加載,當(dāng)父親已經(jīng)加載了該類,那么子ClassLoader就沒有必要加載該class了。 第二:安全因素。
3.獲取當(dāng)前類的類類加載器的方法: - <span style="background-color:rgb(51,153,102)">public ClassLoader findParentClassLoader(){
-
- ClassLoader parent = Thread.currentThread().getContextClassLoader();
- if(parent==null){
- parent = this.getClass().getClassLoader();
- if(parent==null){
- parent = ClassLoader.getSystemClassLoader();
- }
- }
- return parent;
- }</span>
4.類加載器的種類: bootstrap class Loader(引導(dǎo)類加載器) 用來加載java的核心類庫 extensions class loader(擴(kuò)展類加載器) 用來加載java的擴(kuò)展庫Java 虛擬機(jī)的實(shí)現(xiàn)會(huì)提供一個(gè)擴(kuò)展庫目錄。該類加載器在此目錄里面查找并加載 Java 類[ExtClassLoader] 系統(tǒng)類加載器(system class loader)Java 應(yīng)用的類都是由它來完成加載的??梢酝ㄟ^ ClassLoader.getSystemClassLoader() 來獲取它[AppClassLoader]
上一節(jié)主要學(xué)習(xí)了jvm的類加載器,這節(jié)繼續(xù)進(jìn)行,從org.jivesoftware.openfire.starter.ServerStarter文件的第72行進(jìn)行解讀。 System.getProperty("openfire.lib.dir"); 上面這句話是什么意思呢,根據(jù)字面意思理解應(yīng)該是獲取到當(dāng)前項(xiàng)目也就是openfire的lib路徑 繼續(xù)往下讀,如果存放lib的路徑不存在那么就創(chuàng)建一個(gè)存放lib的文件夾 同樣的通過這個(gè)方法可以獲取到其他的屬性 如下列表 java.version | Java 運(yùn)行時(shí)環(huán)境版本 | java.vendor | Java 運(yùn)行時(shí)環(huán)境供應(yīng)商 | java.vendor.url | Java 供應(yīng)商的 URL | java.home | Java 安裝目錄 | java.vm.specification.version | Java 虛擬機(jī)規(guī)范版本 | java.vm.specification.vendor | Java 虛擬機(jī)規(guī)范供應(yīng)商 | java.vm.specification.name | Java 虛擬機(jī)規(guī)范名稱 | java.vm.version | Java 虛擬機(jī)實(shí)現(xiàn)版本 | java.vm.vendor | Java 虛擬機(jī)實(shí)現(xiàn)供應(yīng)商 | java.vm.name | Java 虛擬機(jī)實(shí)現(xiàn)名稱 | java.specification.version | Java 運(yùn)行時(shí)環(huán)境規(guī)范版本 | java.specification.vendor | Java 運(yùn)行時(shí)環(huán)境規(guī)范供應(yīng)商 | java.specification.name | Java 運(yùn)行時(shí)環(huán)境規(guī)范名稱 | java.class.version | Java 類格式版本號(hào) | java.class.path | Java 類路徑 | java.library.path | 加載庫時(shí)搜索的路徑列表 | java.io.tmpdir | 默認(rèn)的臨時(shí)文件路徑 | java.compiler | 要使用的 JIT 編譯器的名稱 | java.ext.dirs | 一個(gè)或多個(gè)擴(kuò)展目錄的路徑 | os.name | 操作系統(tǒng)的名稱 | os.arch | 操作系統(tǒng)的架構(gòu) | os.version | 操作系統(tǒng)的版本 | file.separator | 文件分隔符(在 UNIX 系統(tǒng)中是“/”) | path.separator | 路徑分隔符(在 UNIX 系統(tǒng)中是“:”) | line.separator | 行分隔符(在 UNIX 系統(tǒng)中是“/n”) | user.name | 用戶的賬戶名稱 | user.home | 用戶的主目錄 | user.dir | 用戶的當(dāng)前工作目錄 |
上一節(jié)我們閱讀到了org.jivesoftware.openfire.starter.ServerStarter文件中的第90行,這節(jié)繼續(xù)。 第90行調(diào)用unpackArchives(libDir, true);方法。 通過閱讀該方法的英文注釋大概意思是:轉(zhuǎn)換文件夾中的一些包文件為一個(gè)標(biāo)準(zhǔn)的jar文件,在轉(zhuǎn)換jar文件的同時(shí)每個(gè)被轉(zhuǎn)的包文件就會(huì)被刪除,如果包文件不存在,那么就什么都不做。 帶著這句話我們進(jìn)行閱讀。該方法傳入了2個(gè)參數(shù),第一個(gè)是一個(gè)lib文件夾,第二個(gè)參數(shù)是個(gè)boolean值true。 - File [] packedFiles = libDir.listFiles(new FilenameFilter() {
- public boolean accept(File dir, String name) {
- return name.endsWith(".pack");
- }
- });
-
- if (packedFiles == null) {
-
- return;
- }
以上代碼是unpackArchives方法中的146到155行的代碼。 上面的第一句話我們大家應(yīng)該很熟悉,沒錯(cuò),這句話我也經(jīng)常用,但是我經(jīng)常用不帶參數(shù)的方法也就是一般這樣用, File [] packedFiles = libDir.listFiles();
這樣是獲取到一個(gè)文件夾下的所有的文件。
而帶參數(shù)的根據(jù)字面意思大概是過濾文件名稱的意思,就是過濾一定規(guī)則的文件,而不是顯示所有的文件,
過濾用 FilenameFilter 這個(gè)接口,一般我們用接口都是通過繼承的方法來使用,但是我們現(xiàn)在通過new的方式來使用,其實(shí)這種用法還是蠻多的,比如很多注冊(cè)事件== 很多地方都大量運(yùn)用了該方法。
但是new接口的時(shí)候我們會(huì)發(fā)現(xiàn)我們就要實(shí)現(xiàn)里面所有的方法,少一個(gè)方法都不可以。因?yàn)?code class="java plain">FilenameFilter接口只有一個(gè)方法accept 所以我們?cè)趎ew的同時(shí)就會(huì)實(shí)現(xiàn)該方法,我們通過該方法直接過濾以某種后綴名的文件就可以了現(xiàn)在我們要列出.pack類型的文件所以我們應(yīng)該寫 return name.endsWith( ".pack" ); 就可以獲取到了。很方便吧。 通過以上代碼我們學(xué)習(xí)一個(gè)知識(shí)點(diǎn),那就是獲取某個(gè)文件夾下的某種格式的文件列表應(yīng)該用FilenameFilter 來實(shí)現(xiàn),實(shí)現(xiàn)方法是一下代碼 - File [] packedFiles = libDir.listFiles(new FilenameFilter() {
- public boolean accept(File dir, String name) {
- return name.endsWith(".pack");
- }
- });
如果沒有獲取到.pack類型的文件那么什么都不做,直接返回。 以上的packedFile 是遍歷每個(gè).pack的文件。就這樣把.pack文件轉(zhuǎn)為了jar文件。 第三節(jié)中我們閱讀了org.jivesoftware.openfire.starter.ServerStarter文件到91行,繼續(xù)吧! 這節(jié)我們跳過108行之前的從108行開始學(xué)習(xí),91行到107行相對(duì)比較簡(jiǎn)單。 從第108行到113行主要做了2件事情 第一:加載系統(tǒng)用到的jar包跟zip包到classpath中 第二:通過反射加載org.jivesoftware.openfire.XMPPServer類文件。 一:那么如何加載文件到classpath中呢 openfire用什么加載文件到classpath中:openfire中用org.jivesoftware.openfire.starter.JiveClassLoader加載文件到classpath中(該類是繼承了URLClassLoader) openfire加載文件到classpath的方法: 首先找出jar跟zip類型的文件,代碼如下 1 2 3 4 5 6 7 8 9 10 11 12 13 | File[] jars = libDir.listFiles( new FilenameFilter() {
public boolean accept(File dir, String name) {?
boolean accept = false ;
String smallName = name.toLowerCase();
if (smallName.endsWith( ".jar" )) {
accept = true ;
}
else if (smallName.endsWith( ".zip" )) {
accept = true ;
}
return accept;
}
});
|
然后調(diào)用父類URLClassLoader的addURL方法加載文件到classpath中,代碼如下 1 2 3 4 5 | for ( int i = 0 ; i < jars.length; i++) {
if (jars[i].isFile()) {
addURL(jars[i].toURI().toURL());
}
}
|
二:如何通過反射加載文件? 1 2 3 4 5 6 7 8 | ClassLoader loader = new JiveClassLoader(parent, libDir);
Thread.currentThread().setContextClassLoader(loader);
Class containerClass = loader.loadClass(
"org.jivesoftware.openfire.XMPPServer" );
containerClass.newInstance();
|
到這里org.jivesoftware.openfire.starter.ServerStarter文件都閱讀完畢,ServerStarter中主要做了如下幾件事情:
|