Spring Cloud和Spring Boot深入理解之JAR包项目启动深入理解
项目打包出来的JAR包解读
springboot项目一般打出来是个jar包:

只要用java -jar xxx.jar就可以。

那他是怎么启动的呢,其实里面封装了好多东西,所以我们就来研究下看看吧,我们先把这个jar包解压看看:

然后在linux上看了下结构:
BOOT-INF目录:主要是自己写的应用的字节码文件和项目所引用的依赖包。

META-INF目录:主要是MANIFEST.MF文件。里面有这jar包的入口和启动类

打开MANIFEST.MF可以看到如下,我们平时好像没怎么接触过JarLauncher,那他到底做了什么呢,后面分析:

org目录:spring-boot-loader导入的的依赖包的字节码文件
最后是的文件夹其实就是spring-boot-loader导入的的依赖包的字节码形式,只不过是被复制过来的,为什么不是直接放在引用的jar文件夹下呢,因为需要入口类JarLauncher,根据jar的规范,放在引用jar包下的是不会被启动的,所以要单独复制出来:



总结来说就是三个文件夹:
- BOOT-INF:应用程序的类和要引用的jar包
- META-INF:入口类和启动类的清单文件
- org:spring-boot-loader的导入jar包中的类
jar包是如何启动我们的应用程序的
我们可以用jdwp来对我们运行的jar项目调试,具体jdwp可以百度,其实就是个远程调试啦,我们在5000端口监听客户端连接过来进行调试:

同时在idea里也要设置:

然后开始调试,你会发现他就是从JarLauncher开始启动的:

然后我把一些主要的方法贴一下吧,跟踪调试还是要自己去做,我贴图也不太方便:
执行Launch方法:

getClassPathArchives获取所有的归档包,也就是jar包:

然后准备创建自定义的类加载器,这里就是去加载刚才的归档文件,包含我们的应用程序class文件夹和lib下的jar,转换为url:

然后创建类加载器,是自定义的LaunchedURLClassLoader:

可以看到自定义的加载器就是程序加载的子类:

至于getMainClass()是ExecutableArchiveLauncher类的,其实就是获取了MANIFEST.MF的Start-Class: com.wangwei.SpringBootStudyApplication:

然后调用launch方法:

把要启动的类和类加载器传进去,可以看到他把上下文的类加载器给换了,换成自定义LaunchedURLClassLoader的了,具体里面怎么换的,可以自己去看看:

然后是创建MainMethodRunner实例,并运行run方法,我把这个类贴出来把,就要见到我们的应用程序启动类了:
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.loader;
import java.lang.reflect.Method;
/**
* Utility class that is used by {@link Launcher}s to call a main method. The class
* containing the main method is loaded using the thread context class loader.
*
* @author Phillip Webb
* @author Andy Wilkinson
* @since 1.0.0
*/
public class MainMethodRunner {
private final String mainClassName;
private final String[] args;
/**
* Create a new {@link MainMethodRunner} instance.
* @param mainClass the main class
* @param args incoming arguments
*/
public MainMethodRunner(String mainClass, String[] args) {
this.mainClassName = mainClass;
this.args = (args != null) ? args.clone() : null;
}
public void run() throws Exception {
Class<?> mainClass = Thread.currentThread().getContextClassLoader().loadClass(this.mainClassName);
Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
mainMethod.invoke(null, new Object[] { this.args });
}
}
继续跟进去看看初始化,已经能看到我们的mainClass的名字:

最后运行run方法,其实就使用反射来运行我们应用程序中的静态方法,这样才算启动了:


最后附上点类图帮助理解继承关系和结构:


总结
本篇主要总结了jar包启动项目的流程,里面其实做了很多的事情,springboot自己创建了类加载器来加载,最后还是会启动应用程序,虽然还没涉及到具体springboot内部机制,但是理解这个对整体的把握是有帮助的,希望对你学习springboot有所帮助吧。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。
本文深入解析SpringBoot项目如何通过JAR包启动,详细介绍了JAR包内部结构,包括BOOT-INF、META-INF和org目录的作用,以及JarLauncher如何加载类和启动应用程序。

被折叠的 条评论
为什么被折叠?



