Java ClassLoader類加載器基礎(chǔ)詳解
1. 類加載
- JVM 首次使用某個(gè)類時(shí),需通過(guò) ClassPath 查找該類的 .class 文件
- 將 .class 文件中對(duì)類的描述信息加載到內(nèi)存中,進(jìn)行保存
- 加載時(shí)機(jī)
- 創(chuàng)建對(duì)象
- 創(chuàng)建子類對(duì)象
- 訪問(wèn)靜態(tài)屬性
- 調(diào)用靜態(tài)方法
- 主動(dòng)加載:
Class.forName("full-name")
1.1 class 文件
包名、類名、父類、屬性、方法、構(gòu)造方法.....
2. 類加載器
- 在運(yùn)行期間,如果我們要產(chǎn)生某個(gè)類的對(duì)象,JVM 會(huì)檢測(cè)該類型的 Class 對(duì)象是否已被加載; 如果沒(méi)有加載,JVM 會(huì)根據(jù)類的名稱找到 .class 文件并加載它
- Class 對(duì)象代表 Java 應(yīng)用程序在運(yùn)行時(shí)所加載的類或接口實(shí)例,每加載一個(gè)類,
JVM自動(dòng)生成一個(gè)Class對(duì)象
;
2.1 ClassLoader的分類
- Bootstrap ClassLoader 啟動(dòng)類加載器(引導(dǎo)類加載器)
- ExtClassLoader 擴(kuò)展類加載器(Java9 之后改為 Platform Classloader)
- Application Classloader(系統(tǒng)類加載器或應(yīng)用類加載器)
默認(rèn)的類加載器
- 自定義類加載器,父類加載器為AppClassLoader
2.2 ClassLoader 層次結(jié)構(gòu)
- 系統(tǒng)類加載器
--父-->
擴(kuò)展類加載器--父-->
引導(dǎo)類加載器 - 除了引導(dǎo)類加載器之外,所有的類加載器都有一個(gè)父類加載器。 通過(guò) getParent()方法可以得到
注意:父加載器不是父類
2.3 類與類加載器
- 在JVM中表示兩個(gè)class對(duì)象是否為同一個(gè)類對(duì)象的兩個(gè)必要條件
- 類的全限定名必須一致
- 加載這個(gè)類的ClassLoader必須相同
- 在JVM中,即使這個(gè)兩個(gè)類對(duì)象(class對(duì)象)來(lái)源同一個(gè)Class文件,被同一個(gè)虛擬機(jī)所加載,但只要加載它們的ClassLoader實(shí)例對(duì)象不同,那么這兩個(gè)類對(duì)象也是不相等的
2.3 獲取 ClassLoader
@Test public void getClassLoader() { Class<?> clazz = String.class; ClassLoader classLoader = clazz.getClassLoader(); System.out.println(classLoader); // null, 根加載器并不是由Java語(yǔ)言實(shí)現(xiàn)的,因此拿不到根加載器對(duì)象 }
@Test public void getClassLoader2() throws ClassNotFoundException { // this.getClass().getClassLoader(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); Class<?> clazz = classLoader.loadClass("com.example.concrete.common.domain.User"); System.out.println(classLoader); System.out.println(classLoader.getParent()); }
打印結(jié)果
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@51efea79
2.4 獲得class對(duì)象的三種方法
方式一:對(duì)象.getClass()
String str = "hello"; Class<?> clazz = str.getClass();
方式二:類.classClass<?> clazz = String.class;
方式三:Class. forName() 動(dòng)態(tài)加載類
// 靜態(tài)方法 forName("類的全限定名") Class<?> clazz3 = Class.forName("java.lang.String");
3. ClassLoader 分析
loadClass(String name)
findClass(String name)
defineClass(String name, byte[] b, int off, int len)
// ClassLoader 的默認(rèn)實(shí)現(xiàn)就是雙親委托 public abstract class ClassLoader { //每個(gè)類加載器都有個(gè)父加載器 private final ClassLoader parent; public Class<?> loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); } protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); } protected final Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError { return defineClass(name, b, off, len, null); } }
name: 類的全限定名
public Class<?> loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); } /** * classpath 就是一組目錄的集合;classpath 是 JVM 用到的一個(gè)環(huán)境變量,它用來(lái)指示 JVM 如何搜索class * 在啟動(dòng) JVM 時(shí)設(shè)置 classpath 變量 * java -cp or java -classpath .;C:\work\project1\bin;C:\shared abc.xyz.Hello * 如果不設(shè)置,JVM 默認(rèn)的 classpath 為. 即當(dāng)前目錄 */ String classpath = System.getProperty("java.class.path"); Properties properties = System.getProperties(); Set<String> strings = properties.stringPropertyNames(); for (String string : strings) { System.out.println(string); } /** * 若以“/”開(kāi)頭的,表示要從項(xiàng)目的 ClassPath 開(kāi)始的( /mapper/xxx.xml ), * 如果前面沒(méi)有這個(gè)“/”,那么表示的就是相對(duì)于該類的路徑繼續(xù)往下 */ URL resource = classLoader.getResource(""); // file:/.../target/classes/ URL resource1 = classLoader.getResource("bean.xml"); // file:/.../target/classes/bean.xml
4. Classpath
- lib 和 classes 同屬 classpath,訪問(wèn)優(yōu)先級(jí)為: lib > classes
- Java 項(xiàng)目 /src 目錄下的文件(*.xml, *.properties)編譯后會(huì)放到 WEB-INF/classes 目錄,默認(rèn)的 classpath 就是 WEB-INF/classes
- WEB-INF/ 是資源目錄,客戶端不能直接訪問(wèn)
- Maven 項(xiàng)目 resources 目錄下的文件編譯后在
BOOT-INF/classes
4.1 maven 項(xiàng)目 classpath 路徑
Maven 項(xiàng)目目錄
src |-- main |-- java |-- com.xxx |-- resources |-- application.yml
編譯后目錄
target |-- classes |-- com.xxx |-- application.yml
打包的 jar 解壓后目錄
|-- BOOT-INF |-- classes |-- com.xxx |-- application.yml |-- lib |-- org.springframework.boot.loader...
引用 classpath 路徑下的文件,只需在文件名前加 classpath:
classpath:application-*.xml # 子目錄 classpath:config/*.xml # **/ 表示任意目錄 classpath:**/bean.xml
4.2 classpath vs classpath*
classpath
在當(dāng)前classpath 中查找,只加載第一個(gè) classpath 路徑classpath*
不僅包含 class 路徑, 還包括 jar 文件(classpath目錄)classpath*
會(huì)從所有的classpath中加載文件
classpath:*.xml classpath*:config.xml
以上就是Java ClassLoader類加載器基礎(chǔ)詳解的詳細(xì)內(nèi)容,更多關(guān)于Java ClassLoader類加載器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
如何在IDEA運(yùn)行spark程序(搭建Spark開(kāi)發(fā)環(huán)境)
spark程序可以通過(guò)pom.xml的文件配置,添加spark-core依賴,可以直接在IDEA中編寫(xiě)spark程序并運(yùn)行結(jié)果,這篇文章主要介紹了如何在IDEA運(yùn)行spark程序(搭建Spark開(kāi)發(fā)環(huán)境),需要的朋友可以參考下2024-02-02Java解析xml文件和json轉(zhuǎn)換的方法(DOM4j解析)
相信大家都知道Java解析xml的方法有四種,每種方法都很不錯(cuò),今天通過(guò)本文給大家分享使用DOM4j進(jìn)行解析的方法,文章通過(guò)兩種方法給大家進(jìn)行解析,感興趣的朋友一起看看吧2021-08-08Java數(shù)據(jù)存儲(chǔ)的“雙子星”對(duì)決(Map和Set的區(qū)別)
文章主要介紹了Java中Map和Set兩種數(shù)據(jù)結(jié)構(gòu)的定義、實(shí)現(xiàn)、方法及應(yīng)用場(chǎng)景,Map用于存儲(chǔ)鍵值對(duì),鍵唯一,值可重復(fù);Set用于存儲(chǔ)唯一元素,無(wú)序,兩者都提供了豐富的操作方法,如添加、刪除、查找等,感興趣的朋友一起看看吧2025-02-02java 中如何獲取字節(jié)碼文件的相關(guān)內(nèi)容
這篇文章主要介紹了java 中如何獲取字節(jié)碼文件的相關(guān)內(nèi)容的相關(guān)資料,需要的朋友可以參考下2017-04-04java 實(shí)例化類詳解及簡(jiǎn)單實(shí)例
這篇文章主要介紹了java 實(shí)例化類詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-03-03SpringBoot動(dòng)態(tài)定時(shí)任務(wù)實(shí)現(xiàn)與應(yīng)用詳解
定時(shí)任務(wù)在許多應(yīng)用場(chǎng)景中是必不可少的,特別是在自動(dòng)化任務(wù)執(zhí)行、定期數(shù)據(jù)處理等方面,定時(shí)任務(wù)能極大地提高系統(tǒng)的效率,然而,隨著業(yè)務(wù)需求的變化,定時(shí)任務(wù)的執(zhí)行頻率或時(shí)間點(diǎn)可能需要?jiǎng)討B(tài)調(diào)整,所以本文給大家介紹了SpringBoot動(dòng)態(tài)定時(shí)任務(wù)實(shí)現(xiàn)與應(yīng)用2024-08-08