SpringBoot应用能直接运行java -jar的原因分析
首先明确一点,普通jar包是不能直接运行的,比如工具类jar
要能运行,至少得要一个main函数作为入口吧?
SpringBoot应用确实有个main函数,那么问题来了,java -jar是怎么找到这个main函数运行的?
先说答案
是因为引入了spring-boot-maven-plugin插件
1 2 3 4 | < plugin > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-maven-plugin</ artifactId > </ plugin > |
不信?
现在不使用这个插件,将SpringBoot应用打个jar包
target目录产出文件如下
注意此时的jar体积为3202KB,内容只包含了项目中的代码和resources下的文件
尝试java -jar运行,报错没有主清单属性
这是把spring-boot-maven-plugin插件加上,再次打包
target目录如下
jar包体积变大了!另外多出一个jar.origin,大小和之前jar包的一样
当然我们只需要关系jar即可
查看jar包中的内容,不仅包含了自己写的类(classes),还将依赖的第三方jar包全部装了进来(lib),这种jar被称为fat jar
这时使用java -jar命令,成功运行!
按照常规思路,一定是要找到main方法所在的这个类,然后去运行里面的main方法
其实,当执行java -jar时,会自动去找一个叫MANIFEST.MF的文件,然后根据其中的Main-Class找到入口类,并执行其中的main方法
而SpringBoot的jar包的这个文件,就是spring-boot-maven-plugin这个插件生成的
这个文件中的内容如下
1 2 3 4 5 6 7 8 9 10 11 12 | Manifest-Version: 1.0 Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx Archiver-Version: Plexus Archiver Built-By: yimin Spring-Boot-Layers-Index: BOOT-INF/layers.idx Start-Class: com.example.k8sdemo.K8sDemoApplication Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ Spring-Boot-Version: 2.6.13 Created-By: Apache Maven 3.8.8 Build-Jdk: 1.8.0_392 Main-Class: org.springframework.boot.loader.JarLauncher |
好家伙,Main-Class居然不是我们自己写的那个类
而是org.springframework.boot.loader.JarLauncher
想要查看这个类,先引入以下依赖
1 2 3 4 | < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-loader</ artifactId > </ dependency > |
JarLauncher的main函数以及方法调用如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | public static void main(String[] args) throws Exception { new JarLauncher().launch(args); } protected void launch(String[] args) throws Exception { if (!isExploded()) { JarFile.registerUrlProtocolHandler(); } ClassLoader classLoader = createClassLoader(getClassPathArchivesIterator()); String jarMode = System.getProperty( "jarmode" ); String launchClass = (jarMode != null && !jarMode.isEmpty()) ? JAR_MODE_LAUNCHER : getMainClass(); launch(args, launchClass, classLoader); } @Override protected String getMainClass() throws Exception { String mainClass = getProperty(MAIN, "Start-Class" ); if (mainClass == null ) { throw new IllegalStateException( "No '" + MAIN + "' or 'Start-Class' specified" ); } return mainClass; } protected void launch(String[] args, String launchClass, ClassLoader classLoader) throws Exception { Thread.currentThread().setContextClassLoader(classLoader); createMainMethodRunner(launchClass, args, classLoader).run(); } protected MainMethodRunner createMainMethodRunner(String mainClass, String[] args, ClassLoader classLoader) { return new MainMethodRunner(mainClass, args); } public void run() throws Exception { Class<?> mainClass = Class.forName( this .mainClassName, false , Thread.currentThread().getContextClassLoader()); Method mainMethod = mainClass.getDeclaredMethod( "main" , String[]. class ); mainMethod.setAccessible( true ); mainMethod.invoke( null , new Object[] { this .args }); } |
总结一下就是
- 创建一个自定义的类加载器
LaunchedURLClassLoader
- 使用这个自定义的ClassLoader去加载我们自己写的main方法类,这个类由MANIFEST.MF中Start-Class定义
- 反射获取main方法,然后执行
以上就是SpringBoot应用能直接运行java -jar的原因分析的详细内容,更多关于SpringBoot直接运行java -jar的资料请关注脚本之家其它相关文章!
微信公众号搜索 “ 脚本之家 ” ,选择关注
程序猿的那些事、送书等活动等着你
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 reterry123@163.com 进行投诉反馈,一经查实,立即处理!
相关文章
Java SpringBoot微服务框架验证码报错问题解决方案
这篇文章主要介绍了Java SpringBoot微服务框架验证码报错问题解决方案,包括dockerfile容器操作和完整dockerfile,本文给大家介绍的非常详细,需要的朋友可以参考下2024-08-08SpringBoot @Scope与@RefreshScope注解使用详解
spring的bean管理中,每个bean都有对应的scope。在BeanDefinition中就已经指定scope,默认的RootBeanDefinition的scope是prototype类型,使用@ComponentScan扫描出的BeanDefinition会指定是singleton,最常使用的也是singleton2022-11-11微服务Spring Boot 整合 Redis 实现UV 数据统计的详
这篇文章主要介绍了微服务Spring Boot 整合 Redis 实现 UV 数据统计,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2023-01-01
最新评论