Spring Boot项目的真实程序入口
来源:互联网 发布:淘宝买的战地1激活码 编辑:程序博客网 时间:2024/05/16 21:39
基于 spring-boot-start开发的项目,其程序入口并不是我们开发的业务代码中定义了 main 函数的类,而是 Spring Boot 定义的 JarLauncher 类(下文源码反编译自 spring-boot-loader-1.5.8.RELEASE.jar)。
通常使用 spring boot 进行开发时,会定义类似以下程序入口
@SpringBootApplication/** * This @SpringBootApplication is a convenience annotation that adds all of the following: * @Configuration tags the class as a source of bean definitions for the application context. * @EnableAutoConfiguration tells Spring Boot to start adding beans based on classpath settings, other beans, and various property settings. * @EnableWebMvc Normally you would add @EnableWebMvc for a Spring MVC app, but Spring Boot adds it automatically when it sees spring-webmvc on the classpath. This flags the application as a web application and activates key behaviors such as setting up a DispatcherServlet. * @ComponentScan tells Spring to look for other components, configurations, and services in the hello package, allowing it to find the controllers. * */@ServletComponentScan@EnableTransactionManagement@EnableAsync(proxyTargetClass = true)public class KiApplication { public static void main(String[] args) throws Exception { SpringApplication.run(KiApplication.class, args); }}
然后,通过增加 maven 插件 spring-boot-maven-plugin 可以将开发好的项目打包为可执行的 *.jar ,虽然在开发的代码中定义了main函数,但是不要以为程序就是从这个类开始执行的。因为,如果打开打包的 *.jar 中 /META-INF/MANIFEST.MF 文件查看,就会发现真实的入口类并不是我们定义了main函数的类,而是 org.springframework.boot.loader.JarLauncher 。如下,Main-Class 定义 jar 的入口类,另外扩展了 Start-Class 定义启动类,这才是我们业务代码中定义了main函数的类。
Manifest-Version: 1.0Implementation-Title: kiff-starterImplementation-Version: 1.0-SNAPSHOTArchiver-Version: Plexus ArchiverBuilt-By: zouzhiyuanImplementation-Vendor-Id: *.*.*Spring-Boot-Version: 1.5.8.RELEASEImplementation-Vendor: Pivotal Software, Inc.Main-Class: org.springframework.boot.loader.JarLauncherStart-Class: *.*.*.KiApplicationSpring-Boot-Classes: BOOT-INF/classes/Spring-Boot-Lib: BOOT-INF/lib/Created-By: Apache Maven 3.0.5Build-Jdk: 1.8.0_51Implementation-URL: http://projects.spring.io/spring-boot/kiff-starter /进一步查看 JarLauncher 类的源码可以发现,该类声明的 main 函数 调用了父类的 launch() 方法,并且将 args 参数进行透传。
package org.springframework.boot.loader;import org.springframework.boot.loader.ExecutableArchiveLauncher;import org.springframework.boot.loader.archive.Archive;import org.springframework.boot.loader.archive.Archive.Entry;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() { } protected JarLauncher(Archive archive) { super(archive); } protected boolean isNestedArchive(Entry entry) { return entry.isDirectory()?entry.getName().equals("BOOT-INF/classes/"):entry.getName().startsWith("BOOT-INF/lib/"); } public static void main(String[] args) throws Exception { (new JarLauncher()).launch(args); }}
继续查看 JarLauncher 类继承的 ExecutableArchiveLauncher 类,源代码如下,这个类中的 getMainClass() 方法实际上是在找 MANIFEST.MF 文件中定义的 Start-Class
public abstract class ExecutableArchiveLauncher extends Launcher { private final Archive archive; public ExecutableArchiveLauncher() { try { this.archive = this.createArchive(); } catch (Exception var2) { throw new IllegalStateException(var2); } } protected ExecutableArchiveLauncher(Archive archive) { this.archive = archive; } protected final Archive getArchive() { return this.archive; } 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; } } protected List<Archive> getClassPathArchives() throws Exception { ArrayList archives = new ArrayList(this.archive.getNestedArchives(new EntryFilter() { public boolean matches(Entry entry) { return ExecutableArchiveLauncher.this.isNestedArchive(entry); } })); this.postProcessClassPathArchives(archives); return archives; } protected abstract boolean isNestedArchive(Entry var1); protected void postProcessClassPathArchives(List<Archive> archives) throws Exception { }}
而 ExecutableArchiveLauncher 类又继承了 Launcher,而 Launcher 类中会实例化一个 MainMethodRunner 类,所以,我们项目中定义的 main 函数最张是由 MainMethodRunner 类来执行的,代码如下,通过反射的方式调用 main 函数。
package org.springframework.boot.loader;import java.lang.reflect.Method;public class MainMethodRunner { private final String mainClassName; private final String[] args; public MainMethodRunner(String mainClass, String[] args) { this.mainClassName = mainClass; this.args = args == null?null:(String[])args.clone(); } public void run() throws Exception { Class mainClass = Thread.currentThread().getContextClassLoader().loadClass(this.mainClassName); Method mainMethod = mainClass.getDeclaredMethod("main", new Class[]{String[].class}); mainMethod.invoke((Object)null, new Object[]{this.args}); }}
阅读全文
0 0
- Spring Boot项目的真实程序入口
- spring-boot项目的单元测试
- spring boot的项目安装
- 原 Spring 项目转到 Spring boot 项目的一些变动
- Spring Boot程序的依赖下载耗时
- Spring boot程序的打包和启动
- 一个简单的spring-boot小程序
- spring boot 程序启动缓慢的问题
- spring-boot实现web项目的运行
- Spring Boot新建项目的几个坑
- 一个spring boot 项目大概的步骤
- 创建一个简单的Spring Boot项目
- maven+spring+springmvc+hibernate+easyui的真实项目经历
- 使用Spring框架的12个真实开源项目
- 程序的真正入口
- 小谈安卓的程序入口
- 程序的入口
- 程序真正的入口
- 软件调试笔记10
- 第13周项目1(2)-验证分块查找算法
- ionic 购物车
- 为什么在BMP图片中,像素的排布为BGR
- NFS
- Spring Boot项目的真实程序入口
- [算法分析与设计] leetcode 每周一题: 80. Remove Duplicates from Sorted Array II
- AngluarJS
- Qt for Mac苹果开发中,使用Apple Developer文档
- C++中文件读写的操作
- nginx 配置 https
- 欢迎使用CSDN-markdown编辑器
- android经典源码,仿美团外卖日历签到弹性指示器音乐播放器俄罗斯方块取色器飘落效果悬浮效果源码
- Intellij IDEA 创建Web项目并在Tomcat中部署运行