手机如何运行jar jar包如何运行
Springboot可以说是Java程序员必备技能了,大家都知道Springboot最终可以通过maven打成jar包,然后直接使用java -jar命令运行一个Web工程(或其它) 。这样就避免了原先基于tomcat的web工程的复杂操作 。Springboot能够使Web服务的部署简单到如此程度是因为其内置了Jetty(或Tomcat)服务器,并且在容器启动过程中start该服务器,成功运行Web服务 。
本篇并不是深究内置服务器的启动过程,而是追溯Springboot启动之前到底做了什么?它是如何与我们经常写的@SpringBootApplication注解注释的main方法类绑定起来的?
1、一切的开始相信各位Springbooter一定不会陌生下面的代码,无论是初学Springboot的新同学,或是开始研究Springboot源码的新司机,这段代码几乎是我们的落脚点 。我们如此熟悉它,以至于认为它就是Springboot这个魔法乐园的起点 。但真的是这样吗?
@SpringBootApplication public class Springboot01helloworldApplication {public static void main(String<> args) {SpringApplication.run(Springboot01helloworldApplication.class, args);} }复制代码我们都知道,一个Java工程打包过后,这个jar包的入口描述被写在了/META-INF/MANIFEST.MF文件下,下面让我们来看看这个文件内容:
Manifest-Version: 1.0 Archiver-Version: Plexus Archiver Built-By: MrXu Start-Class: com.vivo.internet.nex.repeater.console.RepeaterConsoleApplication Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ Spring-Boot-Version: 1.5.19.RELEASE Created-By: Apache Maven 3.8.1 Build-Jdk: 1.8.0_281 Main-Class: org.springframework.boot.loader.JarLauncher复制代码文件入口的描述为Main-Class对应的value,即org.springframework.boot.loader.JarLauncher 。那么,接下来我们需要看下这个人类究竟做了什么?
// JarLauncher.java public class JarLauncher extends ExecutableArchiveLauncher {static final String BOOT_INF_CLASSES = "BOOT-INF/classes/";static final String BOOT_INF_LIB = "BOOT-INF/lib/";public JarLauncher() {}// ...省略无关代码public static void main(String<> args) throws Exception {(new JarLauncher()).launch(args);} }复制代码明显的main函数吸引了我们的注意,没错了,这就是入口,看看JarLauncher的空构造并没有任何代码,我们先往它的父类找找:
// ExecutableArchiveLauncher.java public abstract class ExecutableArchiveLauncher extends Launcher {public ExecutableArchiveLauncher() {try {this.archive = this.createArchive();} catch (Exception var2) {throw new IllegalStateException(var2);}}// ...省略 }// Launcher.java public abstract class Launcher {public Launcher() {}// ...省略无关代码 } ?复制代码从代码中可以看出,真正干了事情的父类是ExecutableArchiveLauncher,它在初始化时构造了archive实例,该实例封装了/META-INF/MANIFEST.MF文件的信息 。后面我们也会用到它 。
随后便是launch方法,我们只关系核心执行流程:
// Launcher.java protected void launch(String<> args) throws Exception {JarFile.registerUrlProtocolHandler();ClassLoader classLoader = this.createClassLoader(this.getClassPathArchives());this.launch(args, this.getMainClass(), classLoader); } ? // ExecutableArchiveLauncher.java protected String getMainClass() throws Exception {Manifest manifest = this.archive.getManifest();String mainClass = null;if (manifest != null) {mainClass = manifest.getMainAttributes().getValue("Start-Class");} ?if (mainClass == null) {throw new IllegalStateException("No 'Start-Class' manifest entry specified in " + this);} else {return mainClass;} } ?复制代码这里首先调用子类ExecutableArchiveLauncher的getMainClass方法,主要逻辑就是从/META-INF/MANIFEST.MF文件中获取Start-Class信息,对应上文就是com.vivo.internet.nex.repeater.console.RepeaterConsoleApplication字符串,这样就和我们写的启动类关联上了 。
然后是launch方法的具体执行,launch()首先创建一个MainMethodRunner,将上文获取的Start-Class和透传的参数传递进去,然后调用MainMethodRunner的run方法 。run方法的执行也非常简单,就是加载Start-Class对应的启动类,然后反射调用启动类的main方法 。之后就是容器的初始化过程了 。
// Launcher.java protected void launch(String<> args, String mainClass, ClassLoader classLoader) throws Exception {Thread.currentThread().setContextClassLoader(classLoader);// 这里首先调用createMainMethodRunner创建一个MainMethodRunner实例,将mainClass和args参数传入 。随后调用this.createMainMethodRunner(mainClass, args, classLoader).run(); } protected MainMethodRunner createMainMethodRunner(String mainClass, String<> args, ClassLoader classLoader) {return new MainMethodRunner(mainClass, args); } ? // MainMethodRunner.java public MainMethodRunner(String mainClass, String<> args) {this.mainClassName = mainClass;this.args = args != null ? (String
- WPS如何撤销和恢复
- 苹果x手机电池容量是多少
- 手机64g内存够用吗
- 6.21英寸手机和6.5英寸哪个大
- 电脑如何调节亮度 笔记本亮度调节的方法
- 如何制作大枣年糕
- 手机怎么设置允许弹出窗口
- 欢乐斗地主怎么送好友欢乐豆 欢乐斗地主如何送好友欢乐豆
- 明日方舟怎么在电脑上玩 明日方舟如何在电脑上玩
- 途游斗地主怎么换绑定 途游斗地主如何换绑定
