Spring Boot 打包后的结构
-
jar包就是个压缩包
- 解压缩之后目录结构如下 :
- 可以发现,自己编的类在classes目录。
- 配置文件application.properties就在其下一层,那么,在运行时,就可以明确配置文件是在哪里了,在程序运行的时候,并不是去resource目录找东西。
- 在可执行Jar包中 ,我们不能直接访问
classes
目录,而是应该通过类加载器来获取资源的输入流 。这样我们就可以在可执行Jar包中输出classes
目录中的特定资源文件的内容(指定文件名)。 - 如果你需要输出
classes
目录下所有文件的列表,那么目前的Java API无法直接在可执行Jar包中实现这一功能。
-
看看jar包中MAINFEST.FM文件内容:
mfManifest-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
内部代码的简单执行流程:-
Main 方法:
jarlauncher
类中有一个main
方法,这是 Java 程序的入口点。当你运行java -jar
命令时,Java 运行时会首先找到jarlauncher
类并执行它的main
方法。 -
准备执行环境: 在
main
方法中,jarlauncher
首先会准备执行环境,包括设置类加载器、加载应用程序的 JAR 文件以及解析启动参数等。 -
加载应用程序类: 接下来,
jarlauncher
会使用自定义的类加载器 加载应用程序的类。该类加载器继承 自 Java 的URLClassLoader
,它能够加载 JAR 文件中的类。
URLClassLoader
的工作原理是通过指定一个或多个 URL 地址来加载类文件和资源文件。这些 URL 地址可以是文件系统路径、JAR 文件、HTTP 地址等,通过这些 URL 可以将类文件或资源文件加载到 Java 虚拟机中。URLClassLoader
的用法通常是将需要加载的类或资源所在的 JAR 文件或路径添加到类加载器的 URL 数组中,然后通过该类加载器来加载所需的类和资源。这样,Java 虚拟机就能在运行时动态加载指定的类和资源。- JAR 文件是一种压缩文件格式,其中的类和资源被打包成一个归档文件,不能通过普通的 URL 直接访问其中的内容 。所以需要自定义一个
LaunchedURLClassLoader
。 - 对于
jarlauncher
,它实际上是在运行时解析 JAR 文件,并提取其中的应用程序类和依赖的类。它使用了自定义的类加载器来加载 JAR 文件中的类,并通过 Java 反射等机制来实现动态加载和执行应用程序。
-
定位主类:
jarlauncher
会从应用程序 JAR 的META-INF/MANIFEST.MF
文件中读取Main-Class
属性,找到 Spring Boot 应用程序的主类,即包含main
方法的类。 -
执行应用程序: 一旦找到了主类,
jarlauncher
就会通过反射调用主类的main
方法,从而启动 Spring Boot 应用程序。此时,控制权完全交给 Spring Boot 应用,jarlauncher
的任务就完成了。
-
-
它的设计目标是为了提供更好的启动性能和特性支持。
-
总的来说,
jarlauncher
是一个用于启动 Spring Boot 应用程序的加载器,它通过自定义的类加载器加载应用程序的类,并通过反射执行主类的main
方法,从而启动 Spring Boot 应用。它是 Spring Boot 在 2.3 版本中引入的特性,用于提供更好的性能和特性支持。
为什么需要JarLauncher
-
理论上这些流程也可以在应用程序主类启动之后执行,而不一定非要在
jarlauncher
中执行。事实上,在传统的java -jar
启动方式中,所有的流程都是在应用程序主类启动之后进行的。然而,jarlauncher
的引入主要是为了提供更好的特性支持和性能优化,它将一些流程提前到应用程序启动之前执行,从而实现更快的启动速度和更好的用户体验。比如快速验证依赖,提前将错误抛出。 -
具体原因包括:
-
性能优化:
jarlauncher
在设计时考虑了启动性能的优化,通过更高效的类加载和初始化机制,以及减少依赖解析步骤,加快了启动速度。这些优化措施放在应用程序主类启动之前执行,可以减少启动过程中的不必要开销。 -
错误处理和反馈:
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)
-
输入命令行,查看具体的参数
javajava -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"
-
具体流程
-
启动jar包:夹带参数启动
javajava -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:8000 -jar .\springboot-lecture-0.0.1-SNAPSHOT.jar
-
在IDE中操作一下
- 直接debug运行新建的远程调试应用程序。
-