最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Boot 類加載流程分析

 更新時(shí)間:2026年03月11日 10:35:57   作者:d3y1  
本文給大家介紹Spring Boot 類加載流程分析,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧

Java 類加載基礎(chǔ)

類加載器層次結(jié)構(gòu)

Java 虛擬機(jī)使用雙親委派模型(Parent Delegation Model)來加載類:

Bootstrap ClassLoader (啟動(dòng)類加載器)
    ↓
Extension/Platform ClassLoader (擴(kuò)展/平臺(tái)類加載器)
    ↓
Application/System ClassLoader (應(yīng)用/系統(tǒng)類加載器)

雙親委派機(jī)制

雙親委派模型的工作原理:

  1. 當(dāng)一個(gè)類加載器收到類加載請(qǐng)求時(shí),它首先不會(huì)自己去嘗試加載這個(gè)類
  2. 而是把這個(gè)請(qǐng)求委派給父類加載器去完成
  3. 每一個(gè)層次的類加載器都是如此
  4. 只有當(dāng)父加載器反饋?zhàn)约簾o法完成這個(gè)加載請(qǐng)求(找不到所需的類)時(shí),子加載器才會(huì)嘗試自己去加載
protected Class<?> loadClass(String name, boolean resolve) {
    synchronized (getClassLoadingLock(name)) {
        // 1. 檢查是否已經(jīng)加載
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            try {
                if (parent != null) {
                    // 2. 委派給父類加載器
                    c = parent.loadClass(name, false);
                } else {
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // 父類加載器無法加載
            }
            if (c == null) {
                // 3. 自己嘗試加載
                c = findClass(name);
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

Spring Boot 類加載架構(gòu)

為什么需要特殊的類加載器?

Spring Boot 應(yīng)用通常打包為可執(zhí)行的 JAR(Fat JAR 或 Uber JAR),這種 JAR 包含了:

  • 應(yīng)用代碼
  • 所有依賴的第三方庫(kù)
  • Spring Boot 自身的類

傳統(tǒng)的 JAR 加載機(jī)制無法正確處理這種嵌套的 JAR 結(jié)構(gòu),因此 Spring Boot 實(shí)現(xiàn)了自定義的類加載器。

Spring Boot 啟動(dòng)流程

java -jar app.jar
    ↓
JarLauncher.main()
    ↓
創(chuàng)建 LaunchedURLClassLoader
    ↓
設(shè)置 ContextClassLoader
    ↓
調(diào)用應(yīng)用程序的 Main 方法

核心類

Spring Boot 類加載相關(guān)的核心類位于 org.springframework.boot.loader 包:

類名作用
JarLauncher可執(zhí)行 JAR 的啟動(dòng)器
WarLauncher可執(zhí)行 WAR 的啟動(dòng)器
LaunchedURLClassLoaderSpring Boot 自定義的類加載器
JarFile封裝 JAR 文件訪問
JarFileRegisterJAR 文件注冊(cè)表

Fat JAR 結(jié)構(gòu)

目錄結(jié)構(gòu)

Spring Boot 可執(zhí)行 JAR 的內(nèi)部結(jié)構(gòu):

app.jar
├── BOOT-INF/
│   ├── classes/           # 應(yīng)用類文件
│   │   └── com/example/
│   │       └── Application.class
│   └── lib/               # 依賴庫(kù)
│       ├── spring-boot-2.7.0.jar
│       ├── spring-core-5.3.20.jar
│       └── ...
├── META-INF/
│   ├── MANIFEST.MF        # 清單文件
│   └── spring.factories   # Spring 配置
├── org/springframework/boot/loader/  # Spring Boot Loader 類
│   ├── JarLauncher.class
│   ├── LaunchedURLClassLoader.class
│   └── ...
└── [其他資源]

MANIFEST.MF 關(guān)鍵配置

Manifest-Version: 1.0
Start-Class: com.example.Application
Main-Class: org.springframework.boot.loader.JarLauncher
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Version: 2.7.0

關(guān)鍵屬性說明:

  • Main-Class: 指向 Spring Boot 的啟動(dòng)器類
  • Start-Class: 實(shí)際的應(yīng)用程序主類
  • Spring-Boot-Classes: 應(yīng)用類所在目錄
  • Spring-Boot-Lib: 依賴庫(kù)所在目錄

LaunchedURLClassLoader 詳解

繼承關(guān)系

java.lang.ClassLoader
    ↓
java.net.URLClassLoader
    ↓
org.springframework.boot.loader.LaunchedURLClassLoader

核心特性

1. 打破雙親委派

LaunchedURLClassLoader 在某些情況下會(huì)打破傳統(tǒng)的雙親委派模型:

@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
    // 1. 檢查是否已經(jīng)加載
    Class<?> loadedClass = findLoadedClass(name);
    if (loadedClass == null) {
        // 2. 對(duì)于某些包,優(yōu)先從 BOOT-INF 加載
        if (isEligibleForOverride(name)) {
            try {
                loadedClass = findClass(name);
                if (resolve) {
                    resolveClass(loadedClass);
                }
                return loadedClass;
            } catch (ClassNotFoundException e) {
                // 繼續(xù)嘗試父加載器
            }
        }
        // 3. 使用標(biāo)準(zhǔn)的雙親委派
        return super.loadClass(name, resolve);
    }
    return loadedClass;
}

2. URL 處理

LaunchedURLClassLoader 能夠處理嵌套 JAR 的 URL:

jar:file:/path/to/app.jar!/BOOT-INF/lib/spring-core-5.3.20.jar!/

這種 URL 格式表示:

  • 外層 JAR: file:/path/to/app.jar
  • 內(nèi)層 JAR: BOOT-INF/lib/spring-core-5.3.20.jar

3. 資源加載

@Override
public URL findResource(String name) {
    // 優(yōu)先從 BOOT-INF/classes 查找
    URL url = findResourceInBootInf(name);
    if (url != null) {
        return url;
    }
    // 然后從 BOOT-INF/lib 查找
    return findResourceInDependencies(name);
}

類加載優(yōu)先級(jí)

Spring Boot 類加載器的加載優(yōu)先級(jí):

Bootstrap ClassLoader (JDK 核心類)
LaunchedURLClassLoader (BOOT-INF/classes)
LaunchedURLClassLoader (BOOT-INF/lib)
Extension/Platform ClassLoader
Application ClassLoader (其他)

類加載委托模型

Spring Boot 的委托策略

Spring Boot 并非完全打破雙親委派,而是在特定場(chǎng)景下進(jìn)行調(diào)整:

正常情況(遵循雙親委派):
Application ClassLoader → LaunchedURLClassLoader → Bootstrap ClassLoader
特殊情況(打破雙親委派):
對(duì)于 Spring Boot 應(yīng)用類,LaunchedURLClassLoader 優(yōu)先加載

加載決策流程

收到類加載請(qǐng)求
    ↓
是否是 JDK 核心類?
    ↓ 是 → Bootstrap ClassLoader 加載
    ↓ 否
是否是 Spring Boot Loader 類?
    ↓ 是 → Bootstrap ClassLoader 加載
    ↓ 否
是否在 BOOT-INF/classes 中?
    ↓ 是 → LaunchedURLClassLoader 加載
    ↓ 否
是否在 BOOT-INF/lib 中?
    ↓ 是 → LaunchedURLClassLoader 加載
    ↓ 否
委托給父類加載器

類隔離

Spring Boot 的類加載機(jī)制實(shí)現(xiàn)了類隔離:

  • 應(yīng)用類BOOT-INF/classes/
  • 依賴類BOOT-INF/lib/
  • 系統(tǒng)類rt.jar, jce.jar

這種隔離確保了:

  1. 應(yīng)用類不會(huì)被系統(tǒng)類覆蓋
  2. 不同版本的依賴可以共存
  3. 類加載沖突最小化

常見問題與解決方案

1. ClassNotFoundException

問題現(xiàn)象:

java.lang.ClassNotFoundException: com.example.MyClass

可能原因:

  • 類文件不在 BOOT-INF/classes/
  • 依賴 JAR 不在 BOOT-INF/lib/
  • MANIFEST.MF 配置錯(cuò)誤

解決方案:

<!-- Maven 確保正確打包 -->
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

2. NoClassDefFoundError

問題現(xiàn)象:

java.lang.NoClassDefFoundError: org/springframework/core/ResolvableTypeProvider

可能原因:

  • 依賴版本沖突
  • 類加載順序問題
  • 傳遞依賴未正確包含

解決方案:

<!-- 排除沖突依賴 -->
<dependency>
    <groupId>com.example</groupId>
    <artifactId>some-lib</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

3. ClassCastException

問題現(xiàn)象:

java.lang.ClassCastException: com.example.MyClass cannot be cast to com.example.MyClass

可能原因:

  • 同一個(gè)類被不同的類加載器加載
  • 類加載器隔離導(dǎo)致類型不匹配

解決方案:

// 確保使用正確的類加載器
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class<?> clazz = classLoader.loadClass("com.example.MyClass");

4. NoSuchMethodError

問題現(xiàn)象:

java.lang.NoSuchMethodError: org.springframework.util.StringUtils.isEmpty(Ljava/lang/String;)Z

可能原因:

  • 依賴版本不匹配
  • 方法簽名在不同版本中發(fā)生變化

解決方案:

<!-- 使用 dependencyManagement 統(tǒng)一版本 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-framework-bom</artifactId>
            <version>5.3.20</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

5. 資源文件找不到

問題現(xiàn)象:

InputStream is = getClass().getResourceAsStream("/config.properties"); // 返回 null

可能原因:

  • 資源文件打包位置不正確
  • 使用了錯(cuò)誤的類加載器

解決方案:

// 使用正確的加載方式
InputStream is = Thread.currentThread()
    .getContextClassLoader()
    .getResourceAsStream("config.properties");
// 或者使用 ClassPathResource
Resource resource = new ClassPathResource("config.properties");
InputStream is = resource.getInputStream();

最佳實(shí)踐

1. 依賴管理

<!-- 使用 Spring Boot BOM 統(tǒng)一版本 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.7.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

2. 避免類沖突

<!-- 排除不需要的傳遞依賴 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>

3. 自定義類加載器

public class CustomClassLoader extends LaunchedURLClassLoader {
    @Override
    protected Class<?> loadClass(String name, boolean resolve) 
            throws ClassNotFoundException {
        // 自定義加載邏輯
        if (name.startsWith("com.custom.")) {
            Class<?> clazz = findLoadedClass(name);
            if (clazz == null) {
                clazz = findClass(name);
            }
            if (resolve) {
                resolveClass(clazz);
            }
            return clazz;
        }
        return super.loadClass(name, resolve);
    }
}

4. 資源加載最佳實(shí)踐

@Service
public class ResourceService {
    // 推薦:使用 Resource 抽象
    @Value("classpath:config.properties")
    private Resource configResource;
    public void loadConfig() throws IOException {
        Properties props = new Properties();
        try (InputStream is = configResource.getInputStream()) {
            props.load(is);
        }
    }
    // 推薦:使用 ClassPathResource
    public Resource loadResource(String path) {
        return new ClassPathResource(path);
    }
}

5. 調(diào)試類加載問題

@Component
public class ClassLoaderDebugger implements ApplicationListener<ApplicationReadyEvent> {
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        System.out.println("Context ClassLoader: " + classLoader);
        System.out.println("Parent ClassLoader: " + classLoader.getParent());
        // 打印類路徑
        if (classLoader instanceof URLClassLoader) {
            URL[] urls = ((URLClassLoader) classLoader).getURLs();
            System.out.println("Classpath URLs:");
            for (URL url : urls) {
                System.out.println("  " + url);
            }
        }
    }
}

6. JVM 參數(shù)配置

# 啟用類加載詳細(xì)日志
java -verbose:class -jar app.jar
# 設(shè)置類加載器調(diào)試
java -Djava.security.debug=classloader -jar app.jar
# 指定自定義類加載器
java -Djava.system.class.loader=com.example.CustomClassLoader -jar app.jar

總結(jié)

Spring Boot 的類加載機(jī)制是其可執(zhí)行 JAR 功能的核心:

  1. LaunchedURLClassLoader 是核心類加載器,能夠處理嵌套 JAR 結(jié)構(gòu)
  2. Fat JAR 結(jié)構(gòu) 將應(yīng)用類和依賴類組織在 BOOT-INF 目錄下
  3. 類加載策略 在保持雙親委派的同時(shí),針對(duì) Spring Boot 應(yīng)用進(jìn)行了優(yōu)化
  4. 類隔離 確保了應(yīng)用類和依賴類的正確加載順序

理解 Spring Boot 的類加載機(jī)制有助于:

  • 解決類加載相關(guān)的各種問題
  • 優(yōu)化應(yīng)用啟動(dòng)性能
  • 實(shí)現(xiàn)更復(fù)雜的應(yīng)用架構(gòu)
  • 進(jìn)行有效的故障排查

到此這篇關(guān)于Spring Boot 類加載流程分析的文章就介紹到這了,更多相關(guān)springboot類加載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot集成JWT實(shí)現(xiàn)token驗(yàn)證的流程

    SpringBoot集成JWT實(shí)現(xiàn)token驗(yàn)證的流程

    Json web token (JWT), 是為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開放標(biāo)準(zhǔn)((RFC 7519).這篇文章主要介紹了SpringBoot集成JWT實(shí)現(xiàn)token驗(yàn)證,需要的朋友可以參考下
    2020-01-01
  • Springboot中的三個(gè)基本架構(gòu)

    Springboot中的三個(gè)基本架構(gòu)

    這篇文章主要介紹了Springboot中的三個(gè)基本架構(gòu),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Java線程池核心參數(shù)原理及使用指南

    Java線程池核心參數(shù)原理及使用指南

    本文詳細(xì)介紹了Java線程池的基本概念、核心類、核心參數(shù)、工作原理、常見類型以及最佳實(shí)踐,通過理解每個(gè)參數(shù)的含義和工作原理,可以更好地配置線程池,提高系統(tǒng)性能,感興趣的朋友跟隨小編一起看看吧
    2025-12-12
  • java.lang.ArrayIndexOutOfBoundsException數(shù)組越界異常問題解決

    java.lang.ArrayIndexOutOfBoundsException數(shù)組越界異常問題解決

    這篇文章主要給大家介紹了關(guān)于java.lang.ArrayIndexOutOfBoundsException數(shù)組越界異常問題解決的相關(guān)資料,數(shù)組越界訪問是一個(gè)非常嚴(yán)重的問題,文中通過圖文將解決的辦法介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • 在SpringBoot中使用jwt實(shí)現(xiàn)token身份認(rèn)證的實(shí)例代碼

    在SpringBoot中使用jwt實(shí)現(xiàn)token身份認(rèn)證的實(shí)例代碼

    你還不會(huì)在SpringBoot中使用jwt實(shí)現(xiàn)token身份認(rèn)證嗎,本文小編就給大家詳細(xì)的介紹一下在SpringBoot中使用jwt實(shí)現(xiàn)token身份認(rèn)證的實(shí)例代碼,感興趣的同學(xué)可以自己動(dòng)手試一試
    2023-09-09
  • 由ArrayList來深入理解Java中的fail-fast機(jī)制

    由ArrayList來深入理解Java中的fail-fast機(jī)制

    fail-fast俗稱快速失敗,是在多線程進(jìn)行迭代操作時(shí)產(chǎn)生沖突的一種異常拋出機(jī)制,下面我們就由ArrayList來深入理解Java中的fail-fast機(jī)制.
    2016-05-05
  • 基于SpringBoot框架實(shí)現(xiàn)文件上傳下載分享功能

    基于SpringBoot框架實(shí)現(xiàn)文件上傳下載分享功能

    在當(dāng)今的Web應(yīng)用開發(fā)中,文件上傳與下載功能是極為常見且重要的需求,無論是用戶上傳頭像、分享文檔,還是系統(tǒng)生成報(bào)告供用戶下載,都離不開這一功能模塊,SpringBoot作為一款流行的Java開發(fā)框架,為我們提供了簡(jiǎn)潔高效的方式來實(shí)現(xiàn)文件上傳與下載,需要的朋友可以參考下
    2025-06-06
  • 深入理解ContextClassLoader加載器

    深入理解ContextClassLoader加載器

    這篇文章主要介紹了深入理解ContextClassLoader加載器,Thread?context?class?loader存在的目的主要是為了解決parent?delegation機(jī)制下無法干凈的解決的問題,需要的朋友可以參考下
    2023-10-10
  • 純Java代碼實(shí)現(xiàn)流星劃過天空

    純Java代碼實(shí)現(xiàn)流星劃過天空

    本文給大家介紹純java代碼實(shí)現(xiàn)流星劃過天空,包括流星個(gè)數(shù),流星飛行的速度,色階,流星大小相關(guān)變量設(shè)置。對(duì)java流星劃過天空特效代碼感興趣的朋友可以參考下本文
    2015-10-10
  • Java基礎(chǔ)之Stream流原理與用法詳解

    Java基礎(chǔ)之Stream流原理與用法詳解

    從Java1.8開始提出了Stream流的概念,側(cè)重對(duì)于源數(shù)據(jù)計(jì)算能力的封裝,并且支持序列與并行兩種操作方式。本文就來為大家詳細(xì)講講Stream流原理與用法
    2022-08-08

最新評(píng)論

仙桃市| 江油市| 南昌县| 昌宁县| 运城市| 南丰县| 隆化县| 宁城县| 鹿泉市| 芜湖市| 安龙县| 亚东县| 托克逊县| 沁水县| 通州区| 铜陵市| 青冈县| 昌乐县| 孟津县| 凌海市| 阿克陶县| 太白县| 仁布县| 汤阴县| 昌黎县| 祥云县| 江津市| 金乡县| 屏南县| 马边| 宝鸡市| 乐陵市| 怀仁县| 宜章县| 类乌齐县| 驻马店市| 安泽县| 镇安县| 福安市| 岢岚县| 怀宁县|