springboot启动器实现,springboot程序入口
目录
1、一切的开始2、总结
跳羚可以说是爪哇程序员必备技能了,大家都知道跳羚最终可以通过专家打成冲突包,然后直接使用爪哇罐命令运行一个网工程(或其它)。这样就避免了原先基于雄猫的网工程的复杂操作跳羚。能够使网服务的部署简单到如此程度是因为其内置了码头(或Tomcat)服务器,并且在容器启动过程中开始该服务器,成功运行网服务。
本篇并不是深究内置服务器的启动过程,而是追溯跳羚启动之前到底做了什么?它是如何与我们经常写的@SpringBootApplication注解注释的主要的方法类绑定起来的?
1、一切的开始
相信各位跳靴者一定不会陌生下面的代码,无论是初学跳羚的新同学,或是开始研究跳羚源码的新司机,这段代码几乎是我们的落脚点。我们如此熟悉它,以至于认为它就是跳羚这个魔法乐园的起点。但真的是这样吗?
@SpringBootApplication公共类spring boot 01 hello world应用程序{ public static void main(String[]args){ spring应用程序。运行(spring boot 01 hello world应用。class,args);} }我们都知道,一个爪哇工程打包过后,这个冲突包的入口描述被写在了/META-INF/MANIFEST .中频文件下,下面让我们来看看这个文件内容:
清单-版本: 1.0归档程序-版本: MrXu Start-class : com。vivo。互联网。NEX。复读机。控制台。中继器控制台应用程序Spring-Boot-class 3360 Boot-INF/classes/Spring-Boot-lib : Boot-INF/lib/Spring-Boot-version : 1。5 .19 .发行版创建于3360阿帕奇Maven 3.8文件入口的描述为主要级别对应的值,即org。spring框架。靴子。装载机。罐子发射器。那么,接下来我们需要看下这个类究竟做了什么?
//JarLauncher.java公共类jar发射器扩展ExecutableArchiveLauncher { static final String BOOT _ INF _ CLASSES= BOOT-INF/CLASSES/;静态最终字符串BOOT _ INF _ LIB= BOOT-INF/LIB/;public JarLauncher() { } //.省略无关代码公共静态void main(String[] args)抛出异常{ (new JarLauncher()).启动(参数);} }明显的主要的函数吸引了我们的注意,没错了,这就是入口,看看冲突发射器的空构造并没有任何代码,我们先往它的父类找找:
//executablearchivelauncher . Java公共抽象类ExecutableArchiveLauncher扩展launcher { public ExecutableArchiveLauncher(){ try { this。存档=这个。创建存档();} catch(Exception var 2){ throw new IllegalStateException(var 2);} } //.省略}//Launcher.java公共摘要
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[])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((Object)null, this.args); }
2、总结
综上所述,对于Springboot工程,启动类并不是真正的工程入口,他会被真正的入口反射调用其main方法实现Spring容器的启动。工程入口也是Spring的开发人员为我们营造的一种假象,抽象出来的逻辑入口。
到此这篇关于快速掌握SpringBoot应用的启动入口的文章就介绍到这了,更多相关SpringBoot启动入口内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。