Springboot中的jar是怎样的

发布时间:2021-09-29 17:22:12 作者:柒染
来源:亿速云 阅读:153
# Spring Boot中的JAR是怎样的

## 引言

在现代Java开发中,Spring Boot已经成为构建企业级应用的首选框架。其核心特性之一就是能够将应用程序打包成一个独立的、可执行的JAR文件(通常称为"fat JAR"或"uber JAR")。这种打包方式彻底改变了传统Java应用的部署模式,使开发者能够轻松地构建、发布和运行Spring Boot应用。本文将深入探讨Spring Boot JAR的结构、工作原理、创建过程以及相关的高级主题,帮助开发者全面理解这一关键技术。

## 一、传统JAR与Spring Boot可执行JAR的区别

### 1.1 标准JAR文件结构

传统的Java JAR(Java Archive)文件遵循Zip格式,包含编译后的.class文件、资源文件和可选的META-INF/MANIFEST.MF清单文件。典型结构如下:

myapp.jar ├── META-INF │ └── MANIFEST.MF ├── com │ └── example │ └── MyClass.class └── application.properties


清单文件中通常指定Main-Class属性,指示Java虚拟机从哪个类开始执行。

### 1.2 Spring Boot可执行JAR的独特之处

Spring Boot的可执行JAR在标准JAR基础上进行了扩展和创新:

1. **嵌套JAR支持**:采用特殊布局允许JAR中包含其他JAR(依赖库)
2. **自定义类加载器**:使用Launcher类实现独特的嵌套JAR加载机制
3. **分层优化**:支持分层打包以加速容器环境中的启动速度
4. **嵌入式服务器**:默认包含Tomcat/Jetty等Web服务器

这种设计使应用能够真正做到"一次构建,到处运行",无需预先安装服务器或管理复杂的类路径。

## 二、Spring Boot可执行JAR的详细结构

解压一个典型的Spring Boot JAR,我们可以看到以下结构:

springboot-app.jar ├── BOOT-INF │ ├── classes │ │ └── com/example/MyApplication.class │ └── lib │ ├── spring-boot-2.7.3.jar │ ├── spring-core-5.3.22.jar │ └── … ├── META-INF │ ├── MANIFEST.MF │ └── maven/com.example/springboot-app/pom.properties ├── org │ └── springframework │ └── boot │ └── loader │ ├── JarLauncher.class │ ├── LaunchedURLClassLoader.class │ └── … └── application.properties


### 2.1 关键目录解析

1. **BOOT-INF目录**:
   - classes:包含应用程序自身的编译类文件
   - lib:存放所有依赖的第三方库JAR文件

2. **META-INF目录**:
   - MANIFEST.MF:包含特殊的启动配置信息
   - maven:包含从构建系统继承的元数据

3. **org/springframework/boot/loader**:
   - 包含Spring Boot的自定义类加载器实现
   - 负责处理嵌套JAR的加载逻辑

### 2.2 清单文件(MANIFEST.MF)分析

Spring Boot生成的MANIFEST.MF包含以下关键属性:

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

三、Spring Boot JAR的启动机制

3.1 启动流程详解

当执行java -jar springboot-app.jar时,JVM会按照以下顺序工作:

  1. 读取MANIFEST.MF,找到Main-Class(org.springframework.boot.loader.JarLauncher)
  2. 加载并执行JarLauncher的main方法
  3. Launcher创建LaunchedURLClassLoader实例
  4. 类加载器扫描BOOT-INF/lib下的依赖JAR和BOOT-INF/classes下的应用类
  5. 通过反射调用Start-Class(com.example.MyApplication)的main方法
  6. Spring应用上下文启动,自动配置生效

3.2 类加载器的工作原理

Spring Boot的LaunchedURLClassLoader扩展了URLClassLoader,重写了以下关键行为:

  1. 资源查找:优先检查嵌套JAR中的资源
  2. 类加载:支持从嵌套JAR中加载类
  3. URL处理:将嵌套JAR路径转换为特殊的jar:嵌套URL格式

这种设计解决了标准URLClassLoader无法直接加载嵌套JAR中类的问题。

四、构建Spring Boot可执行JAR

4.1 使用Maven插件打包

在pom.xml中配置spring-boot-maven-plugin:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.7.3</version>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

执行打包命令:

mvn clean package

4.2 使用Gradle插件打包

在build.gradle中应用插件并配置:

plugins {
    id 'org.springframework.boot' version '2.7.3'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

bootJar {
    archiveFileName = 'myapp.jar'
    layered {
        enabled = true
    }
}

执行打包:

gradle bootJar

4.3 打包过程的关键步骤

  1. 依赖解析:构建工具解析所有传递性依赖
  2. 资源处理:处理静态资源、模板文件等
  3. JAR重组
    • 创建标准JAR结构
    • 添加BOOT-INF目录
    • 复制依赖到BOOT-INF/lib
    • 生成自定义MANIFEST.MF
  4. 启动器注入:包含Spring Boot的loader类

五、高级特性与定制

5.1 分层JAR(Layer)支持

Spring Boot 2.3+引入了分层JAR概念,优化Docker镜像构建:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <layers>
            <enabled>true</enabled>
        </layers>
    </configuration>
</plugin>

生成的JAR包含layers.idx文件定义分层:

- "dependencies":
  - "BOOT-INF/lib/dependency1.jar"
  - "BOOT-INF/lib/dependency2.jar"
- "spring-boot-loader":
  - "org/"
- "snapshot-dependencies":
  - "BOOT-INF/lib/snapshot1.jar"
- "application":
  - "BOOT-INF/classes/"
  - "BOOT-INF/libs/"

5.2 自定义MANIFEST属性

通过插件配置添加自定义属性:

<plugin>
    <configuration>
        <manifest>
            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
            <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
            <addBuildEnvironmentEntries>true</addBuildEnvironmentEntries>
        </manifest>
    </configuration>
</plugin>

5.3 排除特定依赖

使用exclude元素移除不需要的依赖:

<plugin>
    <configuration>
        <excludes>
            <exclude>
                <groupId>org.unwanted</groupId>
                <artifactId>dependency</artifactId>
            </exclude>
        </excludes>
    </configuration>
</plugin>

六、性能优化与最佳实践

6.1 JAR瘦身策略

  1. 排除开发工具
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
  1. 使用JarLink(Java 9+):
jlink --module-path $JAVA_HOME/jmods:mods \
      --add-modules com.example.app \
      --output customjre
  1. 启用压缩
<plugin>
    <configuration>
        <compress>true</compress>
    </configuration>
</plugin>

6.2 启动速度优化

  1. 组件扫描优化
@ComponentScan(basePackages = "com.myapp")
  1. 延迟初始化
spring.main.lazy-initialization=true
  1. 使用AOT(Spring Native):
mvn spring-boot:build-image

七、常见问题与解决方案

7.1 类加载问题

症状:NoClassDefFoundError或ClassNotFoundException

解决方案: 1. 检查依赖是否真正打包进BOOT-INF/lib 2. 确认没有不兼容的依赖版本 3. 使用mvn dependency:tree分析依赖冲突

7.2 资源加载问题

症状:getResourceAsStream返回null

原因:资源路径需要相对于BOOT-INF/classes

修复

// 使用ClassLoader加载资源
InputStream is = getClass().getClassLoader()
    .getResourceAsStream("templates/index.html");

7.3 大JAR文件问题

优化方案: 1. 使用分层JAR 2. 排除不必要的依赖 3. 拆分微服务 4. 考虑War部署

八、未来发展与替代方案

8.1 Spring Boot 3.0改进

  1. GraalVM原生镜像支持
native-image -jar springboot-app.jar
  1. 更高效的分层机制

  2. 模块化支持改进

8.2 云原生替代方案

  1. Docker多阶段构建
FROM eclipse-temurin:17-jdk as builder
WORKDIR application
COPY . .
RUN ./gradlew bootJar

FROM eclipse-temurin:17-jre
COPY --from=builder application/build/libs/*.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
  1. OCI镜像构建
pack build myapp --builder paketobuildpacks/builder:base

结语

Spring Boot的可执行JAR设计体现了”约定优于配置”的核心理念,通过创新的打包方式和启动机制,极大地简化了Java应用的部署和分发流程。理解其内部工作原理不仅有助于解决实际问题,还能启发我们设计更加优雅的架构。随着云原生技术的发展,Spring Boot的打包策略也在不断进化,但核心思想始终不变:让开发者专注于业务逻辑,而非基础设施的搭建。

附录

A. 常用命令参考

  1. 查看JAR内容:
jar tf springboot-app.jar
  1. 提取特定文件:
jar xf springboot-app.jar BOOT-INF/lib/spring-core-5.3.22.jar
  1. 分析依赖树:
mvn dependency:tree -Dincludes=org.springframework

B. 推荐工具

  1. JD-GUI:可视化查看JAR内容
  2. Spring Boot Actuator:运行时分析依赖
  3. jdeps:Java依赖分析工具

C. 参考资源

  1. Spring Boot官方文档 - 打包
  2. JAR文件规范
  3. 自定义类加载器指南

”`

推荐阅读:
  1. SpringBoot的jar直接运行的方法
  2. Springboot中怎么集成lombok.jar

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

springboot jar

上一篇:.net如何实现ping

下一篇:mysql有效防止删库跑路的方法教程

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》