一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java運行時環境之ClassLoader類加載機制詳解

Java運行時環境之ClassLoader類加載機制詳解

2021-07-09 16:49濤姐濤哥 Java教程

這篇文章主要給大家介紹了關于Java運行時環境之ClassLoader類加載機制的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

背景:聽說classloader類加載機制是進入bat的必經之路。

classloader總述:

普通的java開發其實用到classloader的地方并不多,但是理解透徹classloader類的加載機制,無論是對我們編寫更高效的代碼還是進bat都大有裨益;而從“黃埔軍校”出來的我對classloader的理解都是借鑒了很多書籍和博客,站在了各大博主的肩膀上,感謝你們!上菜,classloader最主要的作用就是將java字節碼文件(后綴為.class)加載到jvm中,jvm在啟動時不會一次性加載所有的class文件,而是根據需要動態加載class文件,畢竟一次性加載太多jar包的class文件jvm吃不消;下面主要研究bootstrap classloader、extention classloader和appclassloader這三種類加載器。

談到classloader就想到我們安裝jdk的時候都會在控制臺輸入java、javac驗證是否安裝成功,而這個javac就是java classloader,測試是否能把java源文件正確編譯成java字節碼文件,下面的截圖就是個javac的小例子,javac之后加載器把java源文件編譯成testclassloader.class字節碼文件。

Java運行時環境之ClassLoader類加載機制詳解

由于下面要講到classloader的加載路徑,這里順便把java的環境變量也復習一遍。

java_home:

指的是安裝jdk的位置,如:java_home="/library/java/javavirtualmachines/jdk1.8.0_191.jdk/contents/home"

path:

配置path(程序的路徑)的作用將就是能夠在命令行窗口直接鍵入程序的名字了,而不再需要鍵入它的全路徑,比如上面代碼中我用的到javac和java兩個命令。如:path=".$path:$java_home/bin" ;就是在java_home路徑上添加了jdk下的bin目錄即可。

classpath:

classpath就是指向jar包的路徑,如:path=".$path:$java_home/bin" ; "."表示當前目錄。

classloader類加載流程:

三個class loader的執行順序是:bootstrap classloder -> extention classloader -> appclassloader;

1、bootstrap classloder是最頂層的加載類,主要是加載核心類庫,也就是%jre_home%\lib下的rt.jar、resources.jar、charsets.jar和class等資源;并且,可以通過啟動jvm時指定-xbootclasspath和路徑來改變bootstrap classloader的加載目錄,下面有個小荔子。

2、extention classloader是擴展的類加載器,其加載的是目錄%jre_home%\lib\ext目錄下的jar包和class文件;它同樣也可以加載-d java.ext.dirs選項指定的目錄。

3、appclass loader是用于加載當前應用的classpath的所有類,其也稱為systemappclass。

另外有興趣的還可以看下launcher類的源碼,源碼中規定了三個加載器的環境屬性分別為b:sun.boot.class.path、e:java.ext.dirs和a:java.class.path;下面通過代碼來簡單測試寫,如圖:

Java運行時環境之ClassLoader類加載機制詳解

打印輸出結果:

bootstrapclassloader:
        /library/java/javavirtualmachines/jdk1.8.0_191.jdk/contents/home/jre/lib/resources.jar:
            /library/java/javavirtualmachines/jdk1.8.0_191.jdk/contents/home/jre/lib/rt.jar:
                /library/java/javavirtualmachines/jdk1.8.0_191.jdk/contents/home/jre/lib/sunrsasign.jar:
                    /library/java/javavirtualmachines/jdk1.8.0_191.jdk/contents/home/jre/lib/jsse.jar:
                        /library/java/javavirtualmachines/jdk1.8.0_191.jdk/contents/home/jre/lib/jce.jar:
                            /library/java/javavirtualmachines/jdk1.8.0_191.jdk/contents/home/jre/lib/charsets.jar:
                                /library/java/javavirtualmachines/jdk1.8.0_191.jdk/contents/home/jre/lib/jfr.jar:
                                    /library/java/javavirtualmachines/jdk1.8.0_191.jdk/contents/home/jre/classes

extclassloader:
        /users/apple/library/java/extensions:
            /library/java/javavirtualmachines/jdk1.8.0_191.jdk/contents/home/jre/lib/ext:
                /library/java/extensions:/network/library/java/extensions:
                    /system/library/java/extensions:/usr/lib/java

appclassloader:
        /tjt/eclipse/workspace/tjt/bin:
            /library/java/javavirtualmachines/jdk1.8.0_191.jdk/contents/home/jre/lib/rt.jar

為了更好的理解三者之間加載的關系,我們來測試一個類的加載器和它的父類加載以及一些不是我們創建的類如string、double、int等基礎類:

Java運行時環境之ClassLoader類加載機制詳解

從上圖中可用看出,自己編寫的類test2.class文件是由appclassloader加載的,并且appclassloader有父加載器extclassloader,但extclassloader的父加載器為null;double.class這個java基礎類的加載器為null,其父加載也為空且程序還會報空指針異常錯誤;其實呢,double.class是有bootstrap classloader加載的,也并不是每個加載器都有父加載器;總的來說就是jvm啟動時通過bootstrap類加載器加載rt.jar等核心jar包中的class文件,諸如一些int.class,string.class都是由它加載;jvm初始化sun.misc.launcher并創建extension classloader和appclassloader實例,且將extclassloader設置為appclassloader的父加載器;而bootstrap雖然沒有父加載器,但是它卻可以作為一個classloader的父加載器;另外,一個classloader創建時如果沒有指定parent,那么它的parent默認就是appclassloader;

雙親委托:

當一個類加載器查找class和resource時,是通過“委托模式”進行的,它首先會判斷這個class是不是已經加載成功,如果沒有加載的話它并不是自己進行查找,而是先通過父加載器,然后遞歸下去,直到bootstrap classloader,如果bootstrap classloader找到了,直接返回,如果沒有找到,則一級一級返回,最后是由自身去查找這些對象;這種機制就叫做雙親委托。

Java運行時環境之ClassLoader類加載機制詳解

從上圖可用看出classloader的加載序列,委托是從下往上,查找過程則是從上向下的,以下有幾個注意事項:

1、一個appclassloader查找資源時,首先會查看緩存是否有,若有則從緩存中獲取,否則委托給父加載器;

2.、重復第一步的遞歸操作,查詢類是否已被加載;

3.、如果extclassloader也沒有加載過,則由bootstrap classloader加載,它首先也會查找緩存,如果沒有找到的話,就去找自己的規定的路徑下,也就是sun.mic.boot.class下面的路徑,找到就返回,找不到就讓子加載器自己去找。

4.、bootstrap classloader如果沒有查找成功,則extclassloader自己在java.ext.dirs路徑中去查找,查找成功就返回,查找不成功則再向下讓子加載器找。

5.、若是extclassloader查找不成功,則由ppclassloader在java.class.path路徑下自己查找查找,找到就返回,如果沒有找到就讓子類找,如果沒有子類則會拋出各種異常。

自定義classloader:

在classloader中有四個很重要實用的方法loadclass()、findloadedclass()、findclass()、defineclass(),可以用來創建屬于自己的類的加載方式;比如我們需要動態加載一些東西,或者從c盤某個特定的文件夾加載一個class文件,又或者從網絡上下載class主內容然后再進行加載等。分三步搞定:

1、編寫一個類繼承classloader抽象類;

2、重寫findclass()方法;

3、在findclass()方法中調用defineclass()方法即可實現自定義classloader;

需求:自定義一個classloader其默認加載路徑為"/tjt/code"下的jar包和資源。首先創建一個test.java,然后javac編譯并把生成的test.class文件放到"/tjt/code"路徑下,然后再編寫一個diskclassloader繼承classloader,最后通過findclassloader的測試類,調用再test.class里面的一個find()方法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package www.baidu;
import java.io.bytearrayoutputstream;
import java.io.file;
import java.io.fileinputstream;
import java.io.ioexception;
 
public class diskclassloader extends classloader{
//自定義classloader能將class二進制內容轉換成class對象
 private string mypath;
 
 public diskclassloader(string path) {
  mypath = path;
 }
 
 //findclass()方法中定義了查找class的方法
 @override
 protected class<?> findclass(string name) throws classnotfoundexception{
  string filename = getfilename(name);
  file file = new file(mypath,filename);
  try {
   fileinputstream is = new fileinputstream(file);
   bytearrayoutputstream bos = new bytearrayoutputstream();
   int len = 0;
   try {
    while((len = is.read()) != -1) {
     bos.write(len);
    }
   } catch (ioexception e) {
    e.printstacktrace();
   }
   byte[] data = bos.tobytearray();
   is.close();
   bos.close();
   //數據通過defineclass()生成了class對象
   return defineclass(name, data,0,data.length );
  } catch (exception e) {
   e.printstacktrace();
  }
  return super.findclass(name);
 }
 
 private string getfilename(string name) {
  int lastindexof = name.lastindexof('.');
  if (lastindexof == -1) {
   return name + ".class";
  }else {
   return name.substring(lastindexof + 1) + ".class";
  }
 }
}

測試結果如下:找到了自定義的加載路徑并且調用了類中的find()方法

Java運行時環境之ClassLoader類加載機制詳解

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package www.baidu;
import java.lang.reflect.method;
 
public class findclassloader {
 public static void main(string[] args) throws classnotfoundexception {
  //創建自定義classloader對象
  diskclassloader diskl = new diskclassloader("/tjt/code");
  system.out.println("classloader is: "+diskl);
  try {
    //加載class文件
   class clazz = diskl.loadclass("www.baidu.test");
   if (clazz != null) {
    object object = clazz.newinstance();
    method declaredmethod = clazz.getdeclaredmethod("find", null);
    //通過反射調用test類的find()方法
    declaredmethod.invoke(object, null);
   }
  } catch (exception e) {
   e.printstacktrace();
  }
 }
}

總結:

除此之外,classloader還可以進行程序加密(比如你寫了比較騷的jar包),這樣我們就可以在程序中加載特定了類,并且這個類只能被我們自定義的加載器進行加載,提高了程序的安全性,但是用的不多;反正我們在項目上是不允許用classloader加密,寧愿裸奔,了解一下。另外就是tomcat的類加載機制也是遵循雙親委派機制的,并且大部分的加載機制和jvm類加載機制一樣,理解了bootstrap classloader、extention classloader和appclassloader這三種加載器后再看tomcat類的加載就可以橫著走了。

好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:https://www.cnblogs.com/taojietaoge/p/10269844.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 91精品国产色综合久久 | 亚洲国产成人精品无码区APP | 日本videossexx日本人 | 免费观看视频在线 | h视频免费高清在线观看 | 亚洲琪琪| 亚洲国产精品久久网午夜小说 | 国产成人免费 | 艾秋麻豆果冻传媒老狼仙踪林 | 天堂色| 精品女同同性视频很黄很色 | 欧美精品综合一区二区三区 | 午夜一区二区免费视频 | 久久99精品久久久久久园产越南 | 人阁色第四影院在线观看 | 国产精品麻豆免费版 | 欧美在线一级片 | caoporn超碰最新地址进入 | 精品麻豆 | 国产精品久久一区 | 四川一级毛片 | 国产综合视频 | 5x社区发源地最新地址 | 欧美高清在线精品一区 | 摔跤成人黄版 | 青青青在线视频 | 欧美日韩亚洲高清不卡一区二区三区 | julia ann多人乱战 | 日韩一区在线观看 | 丁香婷婷在线视频 | 好湿好滑好硬好爽好深视频 | 国产高清视频在线 | 教室里老师好紧h | 欧美日韩高清完整版在线观看免费 | 国产欧美又粗又猛又爽老 | 久久久精品3d动漫一区二区三区 | 成人女人天堂午夜视频 | 青青在线观看视频 | 人生路不在线观看完整版 | 99久久久久久久 | 99爱爱|