日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

詳解Java類動(dòng)態(tài)加載和熱替換

瀏覽:21日期:2022-08-12 14:43:36
目錄前言1. Java的類加載器和雙親委派模型1.1 Java類加載器1.2 雙親委派模型2. Java的類動(dòng)態(tài)加載和卸載2.1 Java類的卸載2.2 自定義類加載器2.3 動(dòng)態(tài)卸載存在的問題3. Java類的熱替換前言

最近,遇到了兩個(gè)和Java類的加載和卸載相關(guān)的問題:

1) 是一道關(guān)于Java的判斷題:一個(gè)類被首次加載后,會(huì)長期留駐JVM,直到JVM退出。這個(gè)說法,是不是正確的?

2) 在開發(fā)的一個(gè)集成平臺(tái)中,需要集成類似接口的多種工具,并且工具可能會(huì)有新增,同時(shí)在不同的環(huán)境部署會(huì)有裁剪(例如對(duì)外提供服務(wù)的應(yīng)用,不能提供特定的采購的工具),如何才能更好地實(shí)現(xiàn)?

針對(duì)上面的第2點(diǎn),我們采用Java插件化開發(fā)實(shí)現(xiàn)。上面的兩個(gè)問題,都和Java的類加載和熱替換機(jī)制有關(guān)。

1. Java的類加載器和雙親委派模型1.1 Java類加載器

類加載器,顧名思義,就是用來實(shí)現(xiàn)類的加載操作。每個(gè)類加載器都有一個(gè)獨(dú)立的類名稱空間,就是說每個(gè)由該類加載器加載的類,都在自己的類名稱空間,如果要比較兩個(gè)類是否“相等”,首先這兩個(gè)類必須在相同的類命名空間,即由相同的類加載器加載(即對(duì)于任何一個(gè)類,都必須由該類本身和加載它的類加載器一起確定其在JVM中的唯一性),不是同一個(gè)類加載器加載的類,不會(huì)相等。

在Java中,主要有如下的類加載器:

詳解Java類動(dòng)態(tài)加載和熱替換

下面,簡(jiǎn)單介紹上面這幾種類加載器:

啟動(dòng)類加載器(Bootstrap Class Loader):這個(gè)類使用C++開發(fā)(所有的類加載器中,唯一使用C++開發(fā)的類加載器),用來加載<JAVA_HOME>/lib目錄中jar和tools.jar或者使用 -Xbootclasspath 參數(shù)指定的類。 擴(kuò)展類加載器(Extension Class Loader):定義為misc.Launcher$ExtClassLoader,用來加載<JAVA_HOME>/lib/ext目錄或者使用java.ext.dir指定的類。 應(yīng)用程序類加載器(Application Class Loader):定義為misc.Launcher$AppClassLoader,用來加載用戶類路徑下面(classpath)下面所有的類,一般情況下,該類是應(yīng)用程序默認(rèn)的類加載器。 用戶自定義類加載器(User Class Loader):用戶自定義類加載器,一般沒有必要,后面我們會(huì)專門來一部分介紹該類型的類加載器。1.2 雙親委派模型

雙親委派模型,是從 Java1.2 開始引入的一種類加載器模式,在Java中,類的加載操作通過java.lang.ClassLoader中的loadClass()方法完成,咱們首先看看該方法的實(shí)現(xiàn)(直接從Java源碼中撈出來的):

protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException {synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); if (c == null) {long t0 = System.nanoTime();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. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment();} } if (resolve) {resolveClass(c); } return c;} }

我們結(jié)合上面的注釋,來解釋下雙親委派模型的內(nèi)容:

1) 接收到一個(gè)類加載請(qǐng)求后,首先判斷該類是否有加載,如果已經(jīng)加載,則直接返回;

2) 如果尚未加載,首先獲取父類加載器,如果可以獲取父類加載器,則調(diào)用父類的loadClass()方法來加載該類,如果無法獲取父類加載器,則調(diào)用啟動(dòng)器加載器來加載該類;

3) 判斷該類是否被父類加載器或者啟動(dòng)類加載器加載,如果已經(jīng)加載完成則返回,如果未成功加載,則自己嘗試來加載該類。

上面的描述,說明了loadClass()方法的實(shí)現(xiàn),我們進(jìn)一步對(duì)上面的步驟進(jìn)行解釋:

因?yàn)轭惣虞d器首先調(diào)父類加載器來進(jìn)行加載,從loadClass()方法的實(shí)現(xiàn),我們知道父類加載器會(huì)嘗試調(diào)自己的父類加載器,直到啟動(dòng)類加載器,所以,任何一個(gè)類的加載,都會(huì)最終委托到啟動(dòng)類加載器來首先加載; 在前面有進(jìn)行介紹,啟動(dòng)類加載器、擴(kuò)展類加載器、應(yīng)用程序類加載器,都有自己加載的類的范圍,例如啟動(dòng)類加載器只加載JDK核心庫,因此并不是父類加載器就可以都加載成功,父類加載器無法加載(一般如上面代碼,拋出來ClassNotFoundException),此時(shí)會(huì)由自己加載。

最后??亂幌攏?俳?幸幌倫芙幔?/p>

雙親委派模型:如果一個(gè)類加載器收到類加載請(qǐng)求,會(huì)首先把加載請(qǐng)求委派給父類加載器完成,每個(gè)層次的類加載器都是這樣,最終所有的加載請(qǐng)求都傳動(dòng)到最根的啟動(dòng)類加載器來完成,如果父類加載器無法完成該加載請(qǐng)求(即自己加載的范圍內(nèi)找不到該類),子類加載器才會(huì)嘗試自己加載。

這樣的雙親委派模型有個(gè)好處:就是所有的類都盡可能由頂層的類加載器加載,保證了加載的類的唯一性,如果每個(gè)類都隨機(jī)由不同的類加載器加載,則類的實(shí)現(xiàn)關(guān)系無法保證,對(duì)于保證Java程序的穩(wěn)定運(yùn)行意義重大。

2. Java的類動(dòng)態(tài)加載和卸載2.1 Java類的卸載

在Java中,每個(gè)類都有相應(yīng)的Class Loader,同樣的,每個(gè)實(shí)例對(duì)象也會(huì)有相應(yīng)的類,當(dāng)滿足如下三個(gè)條件時(shí),JVM就會(huì)卸載這個(gè)類:

1) 該類所有實(shí)例對(duì)象不可達(dá)

2) 該類的Class對(duì)象不可達(dá)

3) 該類的Class Loader不可達(dá)

那么,上面示例對(duì)象、Class對(duì)象和類的Class Loader直接是什么關(guān)系呢?

在類加載器的內(nèi)部實(shí)現(xiàn)中,用一個(gè)Java集合來存放所加載類的引用。而一個(gè)Class對(duì)象總是會(huì)引用它的類加載器,調(diào)用Class對(duì)象的getClassLoader()方法,就能獲得它的類加載器。所以,Class實(shí)例和加載它的加載器之間為雙向引用關(guān)系。

一個(gè)類的實(shí)例總是引用代表這個(gè)類的Class對(duì)象。在Object類中定義了getClass()方法,這個(gè)方法返回代表對(duì)象所屬類的Class對(duì)象的引用。此外,所有的Java類都有一個(gè)靜態(tài)屬性class,它引用代表這個(gè)類的Class對(duì)象。

Java虛擬機(jī)自帶的類加載器(前面介紹的三種類加載器)在JVM運(yùn)行過程中,會(huì)始終存在,而這些類加載器則會(huì)始終引用它們所加載的類的Class對(duì)象,因此這些Class對(duì)象始終是可觸及的。因此,由Java虛擬機(jī)自帶的類加載器所加載的類,在虛擬機(jī)的生命周期中,始終不會(huì)被卸載。

那么,我們是不是就完全不能在Java程序運(yùn)行過程中,動(dòng)態(tài)修改我們使用的類了嗎?答案是否定的!根據(jù)上面的分析,通過Java虛擬機(jī)自帶的類加載器加載的類無法卸載,我們可以自定義類加載器來加載Java程序,通過自定義類加載器加載的Java類,是可以被卸載的。

2.2 自定義類加載器

前面介紹到,類加載的雙親委派模型,是推薦模型,在loadClass中實(shí)現(xiàn)的,并不是必須使用的模型。我們可以通過自定義類加載器,直接加載我們需要的Java類,而不委托給父類加載器。

詳解Java類動(dòng)態(tài)加載和熱替換

如上圖所示,我們有自定義的類加載器MyClassLoader,用來加載類MyClass,則在JVM中,會(huì)存在上面三類引用(上圖忽略這三種類型對(duì)象對(duì)其他的對(duì)象的引用)。如果我們將左邊的三個(gè)引用變量,均設(shè)置為null,那么此時(shí),已經(jīng)加載的MyClass將會(huì)被卸載。

2.3 動(dòng)態(tài)卸載存在的問題

動(dòng)態(tài)卸載需要借助于JVM的垃圾收集功能才可以做到,但是我們知道,JVM的垃圾回收,只有在堆內(nèi)存占用比較高的時(shí)候,才會(huì)觸發(fā)。即使我們調(diào)用了System.gc(),也不會(huì)立即執(zhí)行垃圾回收操作,而只是告訴JVM需要執(zhí)行垃圾回收,至于什么時(shí)候垃圾回收,則要看JVM自己的垃圾回收策略。

但是我們不需要悲觀,即使動(dòng)態(tài)卸載不是那么牢靠,但是實(shí)現(xiàn)動(dòng)態(tài)的Java類的熱替換還是有希望的。

3. Java類的熱替換

下面通過代碼來介紹Java類的熱替換方法(代碼簡(jiǎn)陋,主要為了說明問題):

如下面的代碼:

首先定義一個(gè)自定義類加載器:

package zmj;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;public class FileClassLoader extends ClassLoader { private String fileName; public void setFileName(String fileName) {this.fileName = fileName; } public Class loadClass(String name) throws ClassNotFoundException {if (name.startsWith('java')) { return getSystemClassLoader().loadClass(name);}Class cls = null;File classF = new File(fileName);try { cls = instantiateClass(name, new FileInputStream(classF), classF.length());} catch (IOException e) { e.printStackTrace();}return cls; } private Class instantiateClass(String name, InputStream fin, long len) throws IOException {byte[] raw = new byte[(int) len];fin.read(raw);fin.close();return defineClass(name, raw, 0, raw.length); }}

上面在loadClass時(shí),先判斷類name(包含package的全限定名)是否以java開始,如果是java開始,則使用JVM自帶的類加載器加載。

然后定義一個(gè)簡(jiǎn)單的動(dòng)態(tài)加載類:

package zmj;public class SayHello { public void say() {System.out.println('hello ping...'); }}

在執(zhí)行過程中,會(huì)動(dòng)態(tài)修改打印內(nèi)容,測(cè)試類的熱加載。

然后定義一個(gè)調(diào)用類:

package zmj;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class Main { public static void main(String[] args) throws InterruptedException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {while (true) { FileClassLoader fileClassLoader = new FileClassLoader(); fileClassLoader.setFileName('D:/workspace/idea/test/class-loader-test/target/classes/zmj/SayHello.class'); Object obj = null; obj = fileClassLoader.loadClass('zmj.SayHello').newInstance(); Method m = obj.getClass().getMethod('say', new Class[]{}); m.invoke(obj, new Object[]{}); Thread.sleep(2000);} }}

當(dāng)我們運(yùn)行上面Main程序過程中,我們動(dòng)態(tài)修改執(zhí)行內(nèi)容(SayHello中,從 hello zmj... 更改為 hello ping...),最終展示的內(nèi)容如下:

hello zmj...

hello zmj...

hello zmj...

hello ping...

hello ping...

hello ping...

以上就是詳解Java類動(dòng)態(tài)加載和熱替換的詳細(xì)內(nèi)容,更多關(guān)于Java類動(dòng)態(tài)加載和熱替換的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
视频一区二区中文字幕| 欧美成人基地| 精品捆绑调教一区二区三区| 久久精品国产99国产精品| 奇米狠狠一区二区三区| 亚洲一区二区日韩| 久久香蕉精品| 婷婷综合电影| 国产精品chinese| 青青国产91久久久久久| 日本欧美在线| 欧美激情一区| 日韩一区电影| 激情偷拍久久| 蜜臀精品久久久久久蜜臀| 视频一区国产视频| 国产日韩亚洲| 国产欧美日韩一级| 久久亚洲影院| 国产欧美日韩影院| 久久影院午夜精品| 91久久视频| 国产精品亚洲综合色区韩国 | 91亚洲一区| 欧美 日韩 国产一区二区在线视频| 亚洲激情社区| 国产精品99久久免费| 欧美sm一区| 久久国际精品| 精品免费av在线| 日本精品在线播放| 日韩不卡在线| 欧美一区在线观看视频| 色综合www| 日韩中出av| 亚洲国内欧美| 久久国产欧美日韩精品| 欧美午夜精彩| 捆绑调教美女网站视频一区| 最新日韩欧美| 久久激情网站| 国产精品九九| 亚洲一级大片| 精品欧美激情在线观看| 美腿丝袜亚洲三区| 亚洲精品乱码久久久久久蜜桃麻豆| 精品国产成人| 亚洲人成在线影院| 美女少妇全过程你懂的久久| 免费一级欧美在线观看视频| 一区二区三区网站| 久久精品欧美一区| 久久亚洲国产精品尤物| 91精品一区| 日韩一区精品| 在线看片日韩| 六月婷婷一区| 亚洲一区二区成人| 亚洲国产综合在线看不卡| 日韩一区三区| 日韩精品水蜜桃| 久久久天天操| 日本精品影院| 久久精品亚洲欧美日韩精品中文字幕| 精品国产18久久久久久二百| 国产精品xxx在线观看| 日韩精品免费观看视频| 亚洲字幕久久| 亚洲精品大全| 国产日本亚洲| 精品黄色一级片| 91一区二区三区四区| 日韩a一区二区| 日本高清不卡一区二区三区视频| 久久久久国产精品一区二区| 欧美一区二区性| 久久亚洲美女| 国产麻豆精品久久| 欧美日韩水蜜桃| 久久97视频| 久久久久免费av| 婷婷激情综合| 亚洲人成亚洲精品| 国产精品久久久亚洲一区| 红杏一区二区三区| 蜜臀av免费一区二区三区| 免费久久99精品国产| 国产亚洲一区| 日韩深夜视频| 亚洲自拍另类| 日韩国产欧美视频| 九九色在线视频| 欧美亚洲三级| 另类中文字幕国产精品| 国产精品外国| 高清av一区| 亚洲黄色在线| 国产精品一区二区三区美女| 久久久久91| 国产精品一区亚洲| 国产农村妇女精品一区二区 | 极品日韩av| 国产午夜一区| 91久久视频| 丝袜美腿诱惑一区二区三区| 欧美日韩a区| 国产视频一区三区| 成人亚洲一区二区| 日韩精品视频中文字幕| 免费一二一二在线视频| 亚洲一级淫片| 国产精品成人国产| 日韩精品不卡一区二区| 国产精品一站二站| 亚洲涩涩av| 在线视频精品| 亚洲v在线看| 色综合狠狠操| 久久精品亚洲一区二区| 欧美日韩一区二区三区在线电影| 午夜在线一区| 欧美特黄一区| 一级欧洲+日本+国产| 亚洲精品**中文毛片| 久久天堂影院| 美日韩一区二区三区| 欧美日韩精品一区二区三区在线观看| 五月婷婷六月综合| 91精品99| 亚洲少妇一区| 日韩影院精彩在线| 久久先锋影音| 日日摸夜夜添夜夜添国产精品| 在线看片一区| 国产精品亚洲综合久久| 国产精品17p| 91偷拍一区二区三区精品| 亚洲永久av| 欧美日韩精品一本二本三本| 国产手机视频一区二区| 尤物在线精品| 视频一区二区欧美| 日韩欧美激情电影| 国产精品videossex| 国产精品久久久久久久久久齐齐| 久久超碰99| 久久uomeier| 日本精品不卡| 91成人在线网站| 久久久久九九精品影院| 午夜影院一区| 亚洲一区二区三区高清| 中文字幕一区二区三区在线视频| 国产精品日本一区二区三区在线 | 国产精品红桃| 日韩中文在线电影| 丝袜脚交一区二区| 国产欧美日韩视频在线| 国精品一区二区三区| 久久国产精品色av免费看| 亚洲综合电影| 欧美一区精品| 婷婷综合亚洲| 欧美国产极品| 丝袜a∨在线一区二区三区不卡 | 99国产精品| 国产欧美久久一区二区三区| 欧美精品资源| 美女久久精品| 亚洲欧美久久精品| 精品一区亚洲| 在线看片国产福利你懂的| 日韩 欧美一区二区三区| 久久久久免费av| 国产激情久久| 亚洲精品在线二区| 国内精品99| 精品成人免费一区二区在线播放| 日本精品另类| 综合精品一区| 国产精品腿扒开做爽爽爽挤奶网站| 麻豆久久一区二区| 国产亚洲精品v| 久久99伊人| 99久久99视频只有精品| 久久精品免费看| 日本久久二区| 日本免费在线视频不卡一不卡二| 国产一在线精品一区在线观看| 成人在线免费观看91| 国产日产精品_国产精品毛片 | 视频在线不卡免费观看| 蜜桃精品视频| 国际精品欧美精品| 欧美国产另类| 日本v片在线高清不卡在线观看| 亚洲视频国产| 四虎精品永久免费| 日本亚洲不卡| 97精品国产99久久久久久免费|