我們現場更新時,通常都是提前將后端jar 包替換了,然后到了更新的時間,只需要更新相關的前端文件和修改各種配置,就行了。
但是最近一次更新操作中,忽然發現,提前更新后端包,會存在依賴丟失問題????
文章目錄
- 結論
- docker 容器的掛載邏輯
- 一、掛載類型與實時性
- 二、實時同步的實現機制
- 三、例外情況與注意事項
- 四、驗證實時性的方法
- java -jar 是干什么
- 一、JAR包運行的本質
- 二、實際實現流程
- 三、常見問題與底層機制
- 四、擴展:調試與優化
- 總結
- java 啟動時會將jar 包中那些內容導入內存中
- 一、類文件與元數據
- 二、靜態資源與配置文件
- 三、類加載機制的關鍵階段
- 四、動態加載與內存管理
- 五、優化與注意事項
結論
就是不能換(因為判斷修改是否影響的邏輯比較復雜),之前認為能換,是認為jar 包線上系統不會重新調用相關內容,結合下述相關知識,可以知道,在java 服務運行時,至少有動態加載這種情況時,(開發是動靜分離的,靜態資源應該可以忽略)服務會重新搜索jar 包的相關.class 文件,重新生成類對象。
docker 容器的掛載邏輯
Docker 容器的掛載邏輯是實時同步的,其數據交互機制依賴于宿主機的文件系統通知功能。具體邏輯如下:
一、掛載類型與實時性
- 綁定掛載(Bind Mount)
將宿主機目錄直接映射到容器內,修改任一端(宿主機或容器)的文件會立即同步到另一端。這是最常用的實時掛載方式,適用于開發環境中的代碼熱更新場景12。 - 卷掛載(Volume Mount)
由 Docker 管理的持久化存儲卷,數據存儲在宿主機特定路徑(如<font style="color:rgba(0, 0, 0, 0.9);">/var/lib/docker/volumes</font>
)。與綁定掛載類似,修改實時同步,但更適合生產環境的數據持久化需求49。 - 臨時文件系統(tmpfs)
數據僅存儲在內存中,容器重啟后丟失。雖然數據不持久化,但容器運行期間的讀寫操作也是實時生效的25。
二、實時同步的實現機制
- 文件系統層映射
Docker 通過 Linux 的命名空間(Namespace)和控制組(cgroup)技術,將宿主機的文件系統路徑直接映射到容器內部,底層依賴宿主機文件系統的 inotify 機制實現實時通知911。 - 寫時復制(Copy-on-Write)優化
僅當文件被修改時觸發同步,未修改的文件仍共享宿主機的原始數據層,避免不必要的性能開銷7。
三、例外情況與注意事項
- 網絡文件系統(NFS)延遲
若掛載的是遠程存儲(如 NFS),同步時效性受網絡環境影響,可能出現短暫延遲12。 - 容器內應用緩存
某些應用程序(如數據庫)可能緩存數據到內存,導致文件系統修改不會立即體現在應用層,需手動刷新或重啟服務38。 - 權限問題
若宿主機與容器內用戶權限不匹配(如 UID/GID 不一致),可能導致掛載目錄無法實時寫入610。
四、驗證實時性的方法
可通過以下命令快速測試:
bash# 宿主機操作
echo "test" > /host/path/file.txt # 進入容器查看
docker exec -it container_name cat /container/path/file.txt
若容器內能立即看到更新內容,則證明掛載實時生效12。
總結:Docker 的掛載機制默認是實時同步的,但需結合具體掛載類型和應用場景綜合判斷。對于關鍵業務,建議通過日志或主動監控進一步驗證數據一致性
java -jar 是干什么
通過<font style="color:rgba(0, 0, 0, 0.9);">java -jar</font>
命令運行Java JAR包的本質是通過JVM加載JAR文件中的主類并執行其**<font style="color:rgba(0, 0, 0, 0.9);">main()</font>**
方法,其實現流程可分為以下核心步驟:
一、JAR包運行的本質
- JAR文件結構
JAR包本質是ZIP格式的壓縮文件,包含:- 編譯后的
<font style="color:rgba(0, 0, 0, 0.9);">.class</font>
文件; - 資源文件(如圖片、配置文件);
<font style="color:rgba(0, 0, 0, 0.9);">META-INF/MANIFEST.MF</font>
清單文件(指定主類、依賴路徑等元數據)18。
- 編譯后的
- 清單文件的關鍵作用
<font style="color:rgba(0, 0, 0, 0.9);">MANIFEST.MF</font>
中的<font style="color:rgba(0, 0, 0, 0.9);">Main-Class</font>
屬性決定了入口類,JVM通過此屬性定位并調用指定類的<font style="color:rgba(0, 0, 0, 0.9);">main()</font>
方法。若未正確配置此屬性,會報錯“找不到主清單屬性”14。 - 類加載機制
JVM將JAR包視為一個類路徑(Classpath),通過內置的<font style="color:rgba(0, 0, 0, 0.9);">JarClassLoader</font>
加載其中的類。若依賴其他JAR,需通過<font style="color:rgba(0, 0, 0, 0.9);">-cp</font>
參數顯式指定路徑79。
二、實際實現流程
- 環境檢查
- 檢查系統是否安裝兼容版本的JRE/JDK(通過
<font style="color:rgba(0, 0, 0, 0.9);">java -version</font>
驗證)18。 - 確保
<font style="color:rgba(0, 0, 0, 0.9);">JAVA_HOME</font>
環境變量指向正確的JDK路徑19。
- 檢查系統是否安裝兼容版本的JRE/JDK(通過
- 命令行解析
<font style="color:rgba(0, 0, 0, 0.9);">java -jar</font>
命令觸發JVM啟動,并解析參數:
java -jar yourfile.jar [args...]
- <font style="color:rgba(0, 0, 0, 0.9);">若需指定堆內存或垃圾回收策略,可添加</font>`<font style="color:rgba(0, 0, 0, 0.9);">-Xmx</font>`<font style="color:rgba(0, 0, 0, 0.9);">、</font>`<font style="color:rgba(0, 0, 0, 0.9);">-XX:+UseG1GC</font>`<font style="color:rgba(0, 0, 0, 0.9);">等參數</font>[<font style="color:rgb(22, 119, 255);">1</font>](https://docs.pingcode.com/baike/254964)[<font style="color:rgb(22, 119, 255);">13</font>](https://blog.csdn.net/AttleeTao/article/details/104149794)<font style="color:rgba(0, 0, 0, 0.9);">。</font>
- JAR包加載與清單讀取
- JVM解壓JAR包至臨時目錄(或直接從內存讀取)。
- 解析
<font style="color:rgba(0, 0, 0, 0.9);">META-INF/MANIFEST.MF</font>
文件,提取<font style="color:rgba(0, 0, 0, 0.9);">Main-Class</font>
和<font style="color:rgba(0, 0, 0, 0.9);">Class-Path</font>
(若存在依賴庫)48。
- 主類加載與執行
- 通過反射機制加載
<font style="color:rgba(0, 0, 0, 0.9);">Main-Class</font>
指定的類。 - 調用該類的
<font style="color:rgba(0, 0, 0, 0.9);">public static void main(String[] args)</font>
方法,傳遞命令行參數<font style="color:rgba(0, 0, 0, 0.9);">args</font>
913。
- 通過反射機制加載
- 依賴處理
- 內嵌依賴:若使用Fat JAR(包含所有依賴),直接加載內部類。
- 外部依賴:通過
<font style="color:rgba(0, 0, 0, 0.9);">-cp</font>
參數或<font style="color:rgba(0, 0, 0, 0.9);">MANIFEST.MF</font>
中的<font style="color:rgba(0, 0, 0, 0.9);">Class-Path</font>
指定外部JAR路徑79。
三、常見問題與底層機制
- 權限問題
Linux系統需確保JAR文件有執行權限(<font style="color:rgba(0, 0, 0, 0.9);">chmod +x yourfile.jar</font>
)813。 - 版本兼容性
JVM版本需與編譯JAR包的JDK版本匹配,否則可能報錯<font style="color:rgba(0, 0, 0, 0.9);">UnsupportedClassVersionError</font>
17。 - 進程管理
- 前臺運行:直接執行
<font style="color:rgba(0, 0, 0, 0.9);">java -jar</font>
,關閉終端則進程終止。 - 后臺運行:使用
<font style="color:rgba(0, 0, 0, 0.9);">nohup java -jar &</font>
或<font style="color:rgba(0, 0, 0, 0.9);">javaw</font>
(Windows)實現守護進程313。
- 前臺運行:直接執行
四、擴展:調試與優化
- 調試命令
添加<font style="color:rgba(0, 0, 0, 0.9);">-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005</font>
啟用遠程調試3。 - 性能優化
- 通過
<font style="color:rgba(0, 0, 0, 0.9);">-Xms</font>
和<font style="color:rgba(0, 0, 0, 0.9);">-Xmx</font>
調整堆內存大小。 - 使用
<font style="color:rgba(0, 0, 0, 0.9);">-XX:+HeapDumpOnOutOfMemoryError</font>
生成內存溢出快照113。
- 通過
總結
運行JAR包的本質是JVM根據清單文件定位入口類并執行其主方法,而流程涵蓋環境檢查、文件解析、類加載到程序執行的完整鏈路。理解這一機制有助于解決依賴沖突、版本不兼容等問題,并優化部署流程。
java 啟動時會將jar 包中那些內容導入內存中
ava 啟動時加載 JAR 包中的內容到內存的過程主要涉及類加載機制和資源管理機制。以下是具體會導入內存的內容及加載邏輯:
一、類文件與元數據
- Class 文件
JAR 包中的<font style="color:rgba(0, 0, 0, 0.9);">.class</font>
文件會被類加載器按需加載到內存中,并生成對應的<font style="color:rgba(0, 0, 0, 0.9);">java.lang.Class</font>
對象。- 加載順序:主類及其直接依賴優先加載,其他類延遲加載(例如通過
<font style="color:rgba(0, 0, 0, 0.9);">new</font>
或反射調用時觸發加載)12。 - 存儲區域:類元信息(如方法、字段結構)存儲在方法區(JDK8+ 為元空間 Metaspace),靜態變量存儲在堆內存中的 Class 對象中。
- 加載順序:主類及其直接依賴優先加載,其他類延遲加載(例如通過
- MANIFEST.MF 文件
該文件位于<font style="color:rgba(0, 0, 0, 0.9);">META-INF</font>
目錄下,包含 JAR 包的元數據(如主類定義、類路徑等)。啟動時會解析此文件以確定入口類和依賴關系812。
二、靜態資源與配置文件
- 配置文件
如<font style="color:rgba(0, 0, 0, 0.9);">application.properties</font>
、<font style="color:rgba(0, 0, 0, 0.9);">XML</font>
等文件,通過<font style="color:rgba(0, 0, 0, 0.9);">ClassLoader.getResourceAsStream()</font>
讀取到內存中。但并非所有文件都會被自動加載,需顯式調用資源讀取代碼才會導入11。- 示例:Spring 項目啟動時,通過
<font style="color:rgba(0, 0, 0, 0.9);">FileSystemXmlApplicationContext</font>
加載外部配置文件11。
- 示例:Spring 項目啟動時,通過
- 靜態資源
圖片、模板等非類文件通常通過類路徑訪問,按需加載到內存。例如:
java復制
InputStream is = MyClass.class.getResourceAsStream("/images/logo.png");
三、類加載機制的關鍵階段
- 加載(Loading)
將<font style="color:rgba(0, 0, 0, 0.9);">.class</font>
文件讀入內存,生成<font style="color:rgba(0, 0, 0, 0.9);">Class</font>
對象。類加載器層級包括:- Bootstrap ClassLoader:加載核心 JDK 類(如
<font style="color:rgba(0, 0, 0, 0.9);">java.lang.*</font>
)。 - Extension ClassLoader:加載
<font style="color:rgba(0, 0, 0, 0.9);">jre/lib/ext</font>
目錄下的擴展 JAR。 - System ClassLoader:加載應用類路徑(含用戶 JAR 包)12。
- Bootstrap ClassLoader:加載核心 JDK 類(如
- 連接(Linking)
- 驗證:檢查字節碼是否符合 JVM 規范。
- 準備:為靜態變量分配內存并賦默認值(如
<font style="color:rgba(0, 0, 0, 0.9);">int</font>
初始化為 0)。 - 解析:將符號引用轉為直接引用(如方法實際內存地址)12。
- 初始化(Initialization)
執行靜態代碼塊和顯式靜態變量賦值(如<font style="color:rgba(0, 0, 0, 0.9);">static int a = 5;</font>
)。
四、動態加載與內存管理
- 動態加載
可通過<font style="color:rgba(0, 0, 0, 0.9);">URLClassLoader</font>
在運行時動態加載外部 JAR 包中的類(需調用<font style="color:rgba(0, 0, 0, 0.9);">addURL()</font>
方法)7。例如:
java復制
URLClassLoader loader = new URLClassLoader(new URL[]{new File("lib/external.jar").toURI().toURL()});
Class<?> clazz = loader.loadClass("com.example.ExternalClass");
- 內存區域
- 堆(Heap):存儲對象實例和數組。
- 方法區(Metaspace):存儲類元信息、常量池。
- 棧(Stack):存儲線程方法調用的局部變量和操作數612。
五、優化與注意事項
- 內存參數
可通過 JVM 參數控制內存分配:
bashjava -Xms512m -Xmx1024m -jar app.jar # 設置堆內存初始和最大值[6]()
- 資源釋放
未使用的類可能被垃圾回收(需滿足類卸載條件),但 Metaspace 默認不會主動釋放,需配置<font style="color:rgba(0, 0, 0, 0.9);">-XX:MetaspaceSize</font>
和<font style="color:rgba(0, 0, 0, 0.9);">-XX:MaxMetaspaceSize</font>
。
總結:Java 啟動時主要加載 JAR 包中的類文件、靜態資源和配置文件到內存,具體內容取決于代碼的顯式調用和類依賴關系。類加載器層級和 JVM 內存模型共同決定了資源在內存中的分布與管理。