同步操作将从 guomingc/spring-boot 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
springboot2.3.7.BUILD-SNAPSHOT源码注释 Spring Boot源码解析的重点包括: spring boot自动配置原理 spring boot启动原理 spring boot启动Spring容器源码解析 spring boot启动内置源码解析 外置tomcat启动外置Tomcat启动SpringBoot源码详解 1.spring boot启动原理 java -jar做了什么 根据oracle官网对该命令的描述: 使用-jar参数时,后面的参数是的jar文件名,该jar文件中包含的是class和资源文件。在manifest文件中有Main-Class,它指定了应用的启动类。说白了就是java -jar会去找jar中的manifest文件,在那里面找到Main-Class指定的启动类,然后运行其Main方法; ##SpringBoot的Jar包的打包插件 Spring Boot项目的pom.xml文件中默认使用如下插件(配置在)进行打包:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
spring-boot-maven-plugin项目存在于spring-boot-tools目录中。spring-boot-maven-plugin默认有5个goals:repackage、run、start、stop、build-info。在打包的时候默认使用的是repackage repackage能够将mvn package生成的软件包再次打包为可执行的软件包,并将mvn package生成的软件包重命名为*.original,所以执行以上命令之后,便生成了打包结果对应的两个文件。 ###SpringBoot的jar包中META-INF内容如下
Manifest-Version: 1.0
Implementation-Title: spring-learn
Implementation-Version: 0.0.1-SNAPSHOT
Start-Class: com.tulingxueyuan.Application
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.1.5.RELEASE
Created-By: Maven Archiver 3.4.0
Main-Class: org.springframework.boot.loader.JarLauncher
理论上看,执行java -jar命令时JarLauncher类会被执行,但实际上是com.tulingxueyuan.Application被执行了,另外一个类要被使用必须先被加载,Java没有提供任何标准的方式来加载嵌套的jar文件。这其中发生了什么呢?为什么要这么做呢?在这之前先讲讲以下内容 ###SpringBoot的Archive Archive的概念:archive即归档文件,通常就是一个tar/zip格式的压缩包,而jar是zip格式 SpringBoot抽象了Archive的概念,一个Archive可以是jar(JarFileArchive),可以是一个文件目录(ExplodedArchive),可以抽象为统一访问资源的逻辑层。 SpringBoot定义了一个Archive接口用于描述资源,该接口有两个实现ExplodedArchive和JarFileArchive,分别用于在文件夹目录下寻找资源和在jar包环境下寻找资源。而在SpringBoot打包的fatJar中,使用的时JarFileArchive。 JarFileArchive的数据主要结构为:
public class JarFileArchive implements Archive {
private final JarFile jarFile;
private URL url;
}
JarFile是对jar包的封装,每个JarFileArchive都会对应一个JarFile。JarFile被构造的时候会解析内部结构,去获取jar包里的各个文件或文件夹,这些文件或文件夹会被封装到Entry中,也存储在JarFileArchive中。注意:如果Entry是个jar,会解析成JarFileArchive。
比如springBoot的可执行jar包:
JarFileArchive对应的URL为:
`
jar:file:/Users/format/Develop/gitrepository/springboot-analysis/springboot-executable-jar/target/executable-jar-1.0-SNAPSHOT.jar!/
`
它对应的JarFile为:
`
/Users/format/Develop/gitrepository/springboot-analysis/springboot-executable-jar/target/executable-jar-1.0-SNAPSHOT.jar
`
这个JarFile有很多Entry,比如:
`
META-INF/
META-INF/MANIFEST.MF
spring/
spring/study/
….
spring/study/executablejar/ExecutableJarApplication.class
lib/spring-boot-starter-1.3.5.RELEASE.jar
lib/spring-boot-1.3.5.RELEASE.jar
…
`
JarFileArchive内部的一些依赖jar对应的URL,jar包中包含jar、jar包中包含jar包里面的class文件,会使用 !/ 分隔开如
jar:file:/Users/Format/Develop/gitrepository/springboot-analysis/springboot-executable-jar/target/executable-jar-1.0-SNAPSHOT.jar!/lib/spring-boot-starter-web-1.3.5.RELEASE.jar!/
jar:file:/Users/Format/Develop/gitrepository/springboot-analysis/springboot-executable-jar/target/executable-jar-1.0-SNAPSHOT.jar!/lib/spring-boot-loader-1.3.5.RELEASE.jar!/org/springframework/boot/loader/JarLauncher.class
这种方式只有org.springframework.boot.loader.jar.Handler能处理,它是SpringBoot内部扩展出来的一种URL协议。 ###关于JarLauncher 从MANIFEST.MF可以看到Main函数是JarLauncher,作用是加载内部/BOOT-INF/lib下的jar及/BOOT-INF/classes下的应用class,JarLauncher实现很简单:
public class JarLauncher extends ExecutableArchiveLauncher {
public JarLauncher() {}
public static void main(String[] args) throws Exception {
new JarLauncher().launch(args);
}
}
主入口新建了JarLauncher并调用父类Launcher中的launch方法启动程序. JarLauncher():JarLauncher继承 ExecutableArchiveLauncher,在创建JarLauncher时,父类无参构造方法构建了当前main方法所在的FatJar的JarFileArchive对象。 launch(args): (1)以FatJar为file作为入参,构造JarFileArchive对象。获取其中所有的资源目标,取得其Url,将这些URL作为参数,构建了一个URLClassLoader。 (2)以第一步构建的ClassLoader加载MANIFEST.MF文件中Start-Class指向的业务类,并且执行静态方法main。进而启动整个程序。 另外ExecutableArchiveLauncher 继承了Launcher,在 Launcher 的launch方法中,通过以上archive的getNestedArchives方法找到/BOOT-INF/lib下所有jar及/BOOT-INF/classes目录所对应的archive,通过这些archives的url生成LaunchedURLClassLoader,并将其设置为线程上下文类加载器,启动应用。
###关于URLStreamHandler java中描述资源常使用URL,而URL有一个方法用于打开链接java.net.URL#openConnection()。由于URL用于表达各种各样的资源,打开资源的具体动作由java.net.URLStreamHandler这个类的子类来完成。根据不同的协议,会有不同的handler实现。 SpringBoot对支持从jar in jar中内容读取做了定制,即支持多个!/分隔符的url路径。SpringBoot定制了以下两个方面: 定制java.net.URLStreamHandler的子类Handler,实现识别多个!/分隔符。 定制java.net.JarURLConnection的子类JarURLConnection,打开springboot链接,并获取InputStream的方法。 同时SpringBoot自定义了一套读取ZipFile的工具类和方法实现在定制的JarURLConnection正确获取输入流。
###总结 1.Spring Boot应用通过spring-boot-plugin 打包之后,生成一个Fat jar,包含了应用依赖的jar包和Spring Boot loader相关的类,并 生成了MANIFEST.MF 文件,文件中的main-class 指定运行java -jar的主程序。 2.springbootd的jar包启动时执行的为JarLauncher,它通过加载BOOT-INF/classes目录及BOOT-INF/lib目录下jar文件,实现了fat jar的启动。 其中通过SpringBoot扩展的JarFile、JarURLConnection及URLStreamHandler,实现了jar in jar中资源的加载。 通过SpringBoot扩展的URLClassLoader–LauncherURLClassLoader,实现了jar in jar中class文件的加载。 WarLauncher通过加载WEB-INF/classes目录及WEB-INF/lib和WEB-INF/lib-provided目录下的jar文件,实现了war文件的直接启动及web容器中的启动。
###如何调试JarLauncher 1.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-loader</artifactId>
</dependency>
2.idea中配置JAR APPLICATION idea → Run/Debug Configurations → Search sources using mgdule’s classpath:指定调试的模块 → Path to JAR:指定运行的jar包 → OK → Debug
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。