Spring Boot Jar包与远程调试

Spring Boot 打包后的结构

  • jar包就是个压缩包

    • 解压缩之后目录结构如下 :
    • 可以发现,自己编的类在classes目录。
    • 配置文件application.properties就在其下一层,那么,在运行时,就可以明确配置文件是在哪里了,在程序运行的时候,并不是去resource目录找东西。
    • 在可执行Jar包中 ,我们不能直接访问classes目录,而是应该通过类加载器来获取资源的输入流 。这样我们就可以在可执行Jar包中输出classes目录中的特定资源文件的内容(指定文件名)
    • 如果你需要输出classes目录下所有文件的列表,那么目前的Java API无法直接在可执行Jar包中实现这一功能。
  • 看看jar包中MAINFEST.FM文件内容:

    mf 复制代码
    Manifest-Version: 1.0
    Created-By: Maven JAR Plugin 3.3.0
    Build-Jdk-Spec: 17
    Implementation-Title: springboot-lecture
    Implementation-Version: 0.0.1-SNAPSHOT
    Main-Class: org.springframework.boot.loader.JarLauncher
    Start-Class: com.springboot.lecture.SpringbootLectureApplication
    Spring-Boot-Version: 3.1.0
    Spring-Boot-Classes: BOOT-INF/classes/
    Spring-Boot-Lib: BOOT-INF/lib/
    Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
    Spring-Boot-Layers-Index: BOOT-INF/layers.idx

Jar包中的Main-Class 与 Start-Class

Main-Class

  • main()方法明明在启动类中,Main-Class为什么不是SpringbootLectureApplication?

  • 看看JarLauncher是什么,其实就是jar中的软件包org.springframework.boot.loader下面的类,就是上面解压缩后中的org目录。它也算一种依赖包,但是,并不需要在maven中手动的引入,它是在打包的时候自动引入的。

  • 可以手动引入一下maven依赖:

    mvn 复制代码
    <dependency>  
       <groupId>org.springframework.boot</groupId>  
       <artifactId>spring-boot-loader</artifactId>  
    </dependency>
  • JarLauncher 有jar包,那自然也有war包

  • 主要看看JarLauncher的main方法做了什么?

    • 它会调用父类的launch(String[] args)方法
    • 最后会通过反射调用应用程序的main方法

简单说一下JarLauncher的流程

  • jarlauncher 是 Spring Boot 中用于启动应用程序的特殊加载器,它是一个独立的类,位于 org.springframework.boot.loader.JarLauncher 包中。当你使用 java -jar 命令来运行 Spring Boot JAR 包时,实际上是通过 jarlauncher 来启动应用程序。

  • 以下是 jarlauncher 内部代码的简单执行流程:

    1. Main 方法: jarlauncher 类中有一个 main 方法,这是 Java 程序的入口点。当你运行 java -jar 命令时,Java 运行时会首先找到 jarlauncher 类并执行它的 main 方法。

    2. 准备执行环境:main 方法中,jarlauncher 首先会准备执行环境,包括设置类加载器、加载应用程序的 JAR 文件以及解析启动参数等。

    3. 加载应用程序类: 接下来,jarlauncher 会使用自定义的类加载器 加载应用程序的类。该类加载器继承 自 Java 的 URLClassLoader,它能够加载 JAR 文件中的类。

    • URLClassLoader 的工作原理是通过指定一个或多个 URL 地址来加载类文件和资源文件。这些 URL 地址可以是文件系统路径、JAR 文件、HTTP 地址等,通过这些 URL 可以将类文件或资源文件加载到 Java 虚拟机中。
    • URLClassLoader 的用法通常是将需要加载的类或资源所在的 JAR 文件或路径添加到类加载器的 URL 数组中,然后通过该类加载器来加载所需的类和资源。这样,Java 虚拟机就能在运行时动态加载指定的类和资源。
    • JAR 文件是一种压缩文件格式,其中的类和资源被打包成一个归档文件,不能通过普通的 URL 直接访问其中的内容 。所以需要自定义一个LaunchedURLClassLoader
    • 对于 jarlauncher,它实际上是在运行时解析 JAR 文件,并提取其中的应用程序类和依赖的类。它使用了自定义的类加载器来加载 JAR 文件中的类,并通过 Java 反射等机制来实现动态加载和执行应用程序。
    1. 定位主类: jarlauncher 会从应用程序 JAR 的 META-INF/MANIFEST.MF 文件中读取 Main-Class 属性,找到 Spring Boot 应用程序的主类,即包含 main 方法的类。

    2. 执行应用程序: 一旦找到了主类,jarlauncher 就会通过反射调用主类的 main 方法,从而启动 Spring Boot 应用程序。此时,控制权完全交给 Spring Boot 应用,jarlauncher 的任务就完成了。

  • 它的设计目标是为了提供更好的启动性能和特性支持。

  • 总的来说,jarlauncher 是一个用于启动 Spring Boot 应用程序的加载器,它通过自定义的类加载器加载应用程序的类,并通过反射执行主类的 main 方法,从而启动 Spring Boot 应用。它是 Spring Boot 在 2.3 版本中引入的特性,用于提供更好的性能和特性支持。

为什么需要JarLauncher

  • 理论上这些流程也可以在应用程序主类启动之后执行,而不一定非要在 jarlauncher 中执行。事实上,在传统的 java -jar 启动方式中,所有的流程都是在应用程序主类启动之后进行的。然而,jarlauncher 的引入主要是为了提供更好的特性支持和性能优化,它将一些流程提前到应用程序启动之前执行,从而实现更快的启动速度和更好的用户体验。比如快速验证依赖,提前将错误抛出。

  • 具体原因包括:

    1. 性能优化: jarlauncher 在设计时考虑了启动性能的优化,通过更高效的类加载和初始化机制,以及减少依赖解析步骤,加快了启动速度。这些优化措施放在应用程序主类启动之前执行,可以减少启动过程中的不必要开销。

    2. 错误处理和反馈: jarlauncher 提供了更好的错误处理和用户反馈。它能够更清晰地显示启动过程中的错误信息,并提供详细的日志和调试信息,有助于快速定位和解决问题。这些错误处理机制在应用程序主类启动之前执行,可以更早地发现和处理问题。

  • 总的来说,jarlauncher 将一些处理逻辑提前到应用程序主类启动之前执行,以提供更好的特性支持和性能优化。虽然理论上这些流程也可以在主类启动之后执行,jarlauncher 的设计目标是在应用程序启动之前就能进行一些必要的准备工作,从而实现更好的用户体验和性能表现

  • 因为Jar包运行应用程序的main方法,是通过JarLauncher通过反射调用的,那么应用程序的类加载器就JarLauncher中的自定义类加载器。

  • 可以用代码验证一下:

    java 复制代码
    @SpringBootApplication  
    public class SpringbootLectureApplication {  
    
      public static void main(String[] args) {  
        System.out.println(SpringbootLectureApplication.class.getClassLoader());  
        SpringApplication.run(SpringbootLectureApplication.class, args);  
      }  
    }
    • 运行jar包的类加载器
    • IDE直接运行的类加载器

远程调试Jar包

JDWP(Java Debug Wire Protocol

  • 输入命令行,查看具体的参数

    java 复制代码
    java -agentlib:jdwp=help
    • 远程的Jar需要listen,debug的工具需要attach。
    • 远程的jar启动时需要使用参数选项 server=y
    • 如果是War包:
      • 要改服务器tomcat的配置,修改catalina.sh文件,在顶部加入这样一行配置CATALINA_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"
  • 具体流程

    1. 启动jar包:夹带参数启动

      java 复制代码
       java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:8000 -jar .\springboot-lecture-0.0.1-SNAPSHOT.jar
    2. 在IDE中操作一下

    • 直接debug运行新建的远程调试应用程序。
相关推荐
杨哥带你写代码18 分钟前
足球青训俱乐部管理:Spring Boot技术驱动
java·spring boot·后端
A尘埃1 小时前
SpringBoot的数据访问
java·spring boot·后端
yang-23071 小时前
端口冲突的解决方案以及SpringBoot自动检测可用端口demo
java·spring boot·后端
代码之光_19801 小时前
SpringBoot校园资料分享平台:设计与实现
java·spring boot·后端
苹果醋32 小时前
快速玩转 Mixtral 8x7B MOE大模型!阿里云机器学习 PAI 推出最佳实践
spring boot·nginx·毕业设计·layui·课程设计
程序员大金3 小时前
基于SpringBoot+Vue+MySQL的装修公司管理系统
vue.js·spring boot·mysql
【D'accumulation】4 小时前
令牌主动失效机制范例(利用redis)注释分析
java·spring boot·redis·后端
2401_854391084 小时前
高效开发:SpringBoot网上租赁系统实现细节
java·spring boot·后端
wxin_VXbishe4 小时前
springboot合肥师范学院实习实训管理系统-计算机毕业设计源码31290
java·spring boot·python·spring·servlet·django·php
OEC小胖胖4 小时前
Spring Boot + MyBatis 项目中常用注解详解(万字长篇解读)
java·spring boot·后端·spring·mybatis·web