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运行新建的远程调试应用程序。
相关推荐
佳佳_1 小时前
Spring Boot SSE 示例
spring boot·后端
Yuanymoon1 小时前
【由技及道】统一封装API返回结果后String返回报错文件解决原理--Spring 消息转换器的层次图解与规则说明【人工智障AI2077的开发问题日志002】
java·spring
臣妾写不来啊1 小时前
使用dify的api连接外部知识库,dify连接ragflow的知识库(附java代码)
java·开发语言·spring boot
李长渊哦2 小时前
Spring Boot 接口延迟响应的实现与应用场景
spring boot·后端·php
Cent'Anni2 小时前
【RabbitMQ】事务
java·spring boot·rabbitmq
小杨4042 小时前
springboot框架项目应用实践五(websocket实践)
spring boot·后端·websocket
浪九天3 小时前
Java直通车系列28【Spring Boot】(数据访问Spring Data JPA)
java·开发语言·spring boot·后端·spring
一只爱打拳的程序猿3 小时前
【SpringBoot】实现登录功能
javascript·css·spring boot·mybatis·html5
Huooya4 小时前
Spring的基础事务注解@Transactional
数据库·spring·面试
源码姑娘6 小时前
基于协同过滤算法的音乐推荐系统(源码+部署教程)
spring boot·毕业设计