执行Java -jar somefile.jar时发生了什么(一)

Spring Boot项目Maven打包全攻略:从Fat Jar到Docker分层构建 在Java应用开发中,依赖管理和打包部署是保障应用可移植性与一致性的核心环节。其原理在于通过构建工具将项目代码与第三方库组织成可独立运行的部署单元。这一技术对于实现持续集成、环境标准化和云原生部署具有关键价值,广泛应用于微服务架构、容器化部署等场景。本文聚焦于Spring Boot项目,深入解析如何使用Maven插件实现高效打包。通过对比Fat Jar、Thin Jar及Docker分层镜像等不同策略,并结合依赖冲突、资源路径等高频问题,提供从基础配置到CI/CD集成的实战指南,帮助开发者构建可靠、高效的部 阅读详情


最近在阅读JVM源码,把一些心得写成Blog分享出来,于是便新开了这么一个专题。


第一篇文章取名字的时候让我非常困惑,我代码的阅读是从Launcher开始入手的,也就是Java.exe(如果是windows平台的话)对应的相关代码,但我又不能取“JVM启动过程分析”之类的名字,因为从分析主流程的角度来讲还深不到这个层次,所以就暂且起了这么一个奇怪的名字。


这个系列如果能继续下去的话,不加特殊说明,使用的JDK和JVM版本均为8u20,下载地址来自OpenJDK:http://hg.openjdk.java.net/jdk8u


本人是一个JAVA程序员,在分析JVM大量C/C++时难免会有不妥当的地方,还希望各位读者指正。介于时间有涯而代码“无涯”,具体的实现细节不可能面面俱到,只着重分析和看懂大致流程和机制,如果有比较重要的细节遗漏之处,欢迎留言讨论。


在这个系列中,任何对源文件位置的描述都使用相对路径,其中jdk/代表放置Jdk源码的根目录,hotspot/代表放置jvm源码的根目录。


一、Launcher代码分析

(1)Main.c中的main

位置:jdk/src/bin/main.c 

当我们调用java命令时,首先肯定进入的是C/C++的main函数,就像若干年前我写的那个helloworld一样。

这个main函数位于jdk/src/bin/main.c,在JDK8中是放置在这个位置,在以前较老版本是放在JVM相关代码中的。

main.c中几乎没有实质的逻辑,主要是复制一些参数,处理在windows平台中的一些调用,之后就把各参数传递给JLI_launch进行执行。相关代码在第125行。

return JLI_Launch(margc, margv,
                   sizeof(const_jargs) / sizeof(char *), const_jargs,
                   sizeof(const_appclasspath) / sizeof(char *), const_appclasspath,
                   FULL_VERSION,
                   DOT_VERSION,
                   (const_progname != NULL) ? const_progname : *margv,
                   (const_launcher != NULL) ? const_launcher : *margv,
                   (const_jargs != NULL) ? JNI_TRUE : JNI_FALSE,
                   const_cpwildcard, const_javaw, const_ergo_class);



(2)java.c中的JLI_Launch

位置:jdk/src/bin/java.c

java.c中根据注释可以大概看出这个函数的各参数含义:

JLI_Launch(int argc, char ** argv,              /* main argc, argc */
        int jargc, const char** jargv,          /* java args */
        int appclassc, const char** appclassv,  /* app classpath */
        const char* fullversion,                /* full version defined */
        const char* dotversion,                 /* dot version defined */
        const char* pname,                      /* program name */
        const char* lname,                      /* launcher name */
        jboolean javaargs,                      /* JAVA_ARGS */
        jboolean cpwildcard,                    /* classpath wildcard*/
        jboolean javaw,                         /* windows-only javaw */
        jint ergo                               /* ergonomics class policy */

在第236行调用系统函数获取环境变量,给jrepath,jvmpath和jvmcfg赋值。(每个Java基础教程里设置的环境变量在这里起作用)

    CreateExecutionEnvironment(&argc, &argv,
                               jrepath, sizeof(jrepath),
                               jvmpath, sizeof(jvmpath),
                               jvmcfg,  sizeof(jvmcfg));

第248行加载jvm.dll这个文件,只是加载文件到内存,并没有执行任何操作,同时给这个ifn结构体赋值(根据dll抽取函数调用地址赋值),ifn结构体包含三个关键的函数指针。

if (!LoadJavaVM(jvmpath, &ifn)) {
        return(6);
    }
Ifn结构如下:

typedef struct {
    CreateJavaVM_t CreateJavaVM;
    GetDefaultJavaVMInitArgs_t GetDefaultJavaVMInitArgs;
    GetCreatedJavaVMs_t GetCreatedJavaVMs;
} InvocationFunctions;
根据函数名可以大概猜到,第一个是创建虚拟机,第二个是获取初始参数,第三个是创建很多虚拟机?(vms代表虚拟机的复数形式?我猜的。。)。

之后又对参数进行了一些额外的处理(包括获取classpath、打印调试信息、添加额外的参数等等),在299行调用JVMInit初始化虚拟机

    return JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret);


(3)Java.c中的JVMInit

位置:jdk/src/bin/java.c

代码很少,首先打印一下信息,然后调用ConitueInNewThread函数,从函数名也可以看出,会启用一个新线程建立JVM。

int
JVMInit(InvocationFunctions* ifn, jlong threadStackSize,
        int argc, char **argv,
        int mode, char *what, int ret)
{
    ShowSplashScreen();
    return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
}


(4)Java.c中的ContinueInNewThread

位置:jdk/src/bin/java.c

这个函数依然没做啥东西,就是封装了一下参数,然后委派给ContinueInNewThread0。而ContinueInNewThread0开启一个新的线程,执行JavaMain函数。


(5)Java.c中的JavaMain

位置:jdk/src/bin/java.c

首先在第371行初始化JVM,而InitializeJVM函数做的工作就是调用ifn->createJavaVM,具体的JVM启动过程水太深因此不在这里进行分析。如果初始化成功,则会给vm对象和env对象赋值,其中env是一个非常重要的对象,进行JNI调用的时候会频繁用到。

if (!InitializeJVM(&vm, &env, &ifn)) {
        JLI_ReportErrorMessage(JVM_ERROR1);
        exit(1);
    }
之后检查一下是否传入了Jar文件或者一个类名,如果没有的话就打印一下Usage

之后第439行获取主类,获取主类的方式挺有意思的,在后面会进行分析。接着看看是否抛异常,如果抛异常就直接退出了。

    mainClass = LoadMainClass(env, mode, what);
    CHECK_EXCEPTION_NULL_LEAVE(mainClass);


随后针对JavaFX加载一下东西(如果需要的话),然后获取main这个方法的ID,组合参数,并Invoke,水到渠成。

其中每一步都检查是否有异常抛出。

 mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
                                       "([Ljava/lang/String;)V");
    CHECK_EXCEPTION_NULL_LEAVE(mainID);

    /* Build platform specific argument array */
    mainArgs = CreateApplicationArgs(env, argv, argc);
    CHECK_EXCEPTION_NULL_LEAVE(mainArgs);

    /* Invoke main method. */
    (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);

    /*
     * The launcher's exit code (in the absence of calls to
     * System.exit) will be non-zero if main threw an exception.
     */
    ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1;



(未完待续)






Java SecurityManager访问控制:从权限异常到安全策略配置实战 在Java应用开发中,访问控制是保障系统安全的核心机制之一。其基本原理是通过权限(Permission)模型对代码的敏感操作进行审查,例如文件读写、网络连接等。这一机制的技术价值在于为应用提供了沙箱环境,实现代码执行的最小权限原则,从而防止恶意操作和提升系统安全性。常见的应用场景包括Web服务器中的多应用隔离、插件化系统的动态加载以及容器化环境下的深度防御。当程序抛出AccessControlException时,通常意味着安全策略配置不当或缺失必要权限。本文聚焦于SecurityManager这一传统但广 阅读详情

相关推荐

CVE-2021-21972漏洞深度剖析:从ZIP Slip原理到企业级防御实战

文件上传功能是Web应用中的常见需求,但其安全实现至关重要。其核心原理涉及服务器接收用户提交的文件,并进行存储或解析。如果缺乏严格的安全校验,攻击者可能利用此功能实现恶意操作,技术价值在于理解并防范由此引发的严重安全风险,例如远程代码执行。典型的应用场景包括企业ERP、CRM等系统的报表导入、模板上传等模块。本文以某友NC Cloud报表系统的CVE-2021-21972漏洞为例,深入解析其如何因ZIP文件解压时的目录遍历缺陷,结合JSP文件上传过滤不严,最终导致无需认证的远程命令执行。文章将探讨该漏洞的完

weixin_34293911的博客 385

一文搞懂 java -jar 发生了什么

之前一直就很好奇 java -jar 到底发生了什么,为什么执行 java -jar 代码就自动运行了。今天我们来说明一下,尽量覆盖操作系统、编译原理、JVM 的一些东西。( 本文将处于一个不断更新的状态,知道上面这些东西覆盖的差不多了为止,如果可以的话,也会加上硬件方面的东西 ),主要的目的就是为了能以最简单的 java 代码来串一些相对来说比较底层的东西,让自己以及让每个读者对计算机能有一个相对全局的了解。 我们先约定如下: 1.操作系统仅仅指的是unix 或类unix 2. 64 位机器 3. 64位

shengjk1的博客 2210

Android平台Lua脚本开发:从环境搭建到自动化实战

脚本语言作为轻量级、解释执行的编程工具,在自动化、快速原型和逻辑热更新等场景中具有独特优势。其核心原理是通过嵌入宿主程序或独立解释器,实现动态代码加载与执行,从而提升开发灵活性和效率。在移动开发领域,Android平台对脚本化技术的需求日益增长,特别是在自动化测试、设备管理和轻量级工具开发等应用场景中。本文聚焦于Lua这一轻量高效的脚本语言在Android上的实践,详细解析了通过LuaDroid等集成环境快速上手的路径,并深入探讨了文件操作、系统命令调用等热词相关的自动化脚本编写技巧,为移动端开发者提供了一

读书、思考、生活 514

详解java -jar命令及SpringBoot通过java -jav启动的过程

JarLauncher通过加载BOOT-INF/classes目录及BOOT-INF/lib目录下jar文件,实现了fat jar的启动。 SpringBoot通过扩展JarFile、JarURLConnection及URLStreamHandler,实现了jar in jar中资源的加载。 SpringBoot通过扩展URLClassLoader–LauncherURLClassLoader,实现了jar in jar中class文件的加载。 WarLauncher通过加载WEB-INF/classes目

学英语的程序员 5433

Kali Linux环境下Android移动应用安全测试环境搭建与实战指南

移动应用安全测试是保障应用安全性的重要环节,其核心原理在于通过静态与动态分析技术,深入检测应用代码与运行时行为中存在的潜在漏洞。这项技术的核心价值在于能够主动发现并修复安全缺陷,从而有效提升应用的整体安全防护能力。在实际工程实践中,安全研究人员常借助Kali Linux这一专业的渗透测试平台,集成adb、apktool、Burp Suite、Frida等工具链,构建隔离的测试环境。典型的应用场景包括对Android应用进行授权下的安全评估、漏洞挖掘与合规性检查。本文聚焦于如何在Kali Linux中系统化地

weixin_30595035的博客 338

Android无Root读取应用私有数据的技术路径与安全实践

在Android应用开发中,数据沙盒机制是保障应用间安全隔离的核心设计,它通过为每个应用分配独立的私有存储空间来防止数据被非法访问。其原理基于Linux用户和文件权限系统,确保/data/data/目录下的文件仅对应用自身和Root用户可见。这一机制的技术价值在于保护用户隐私和敏感数据,是构建可信应用生态的基石。然而,在自动化测试、数据迁移或安全审计等特定应用场景下,开发者或测试人员有时需要在无Root权限的条件下,合法地访问特定数据。这催生了对Android系统IPC(进程间通信)机制,特别是Conten

weixin_30402343的博客 444

执行Java -jar somefile.jar时发生了什么(二)

执行Java -jar somefile.jar时发生了什么(二)

锐之锋芒 3794

C++实现SM4国密算法实战指南

通过以上实现,开发者可以快速在C++项目中集成SM4国密算法,满足金融、政务等领域的安全需求。实际部署时建议通过国家密码管理局的合规性检测,并定期更新密钥管理策略。库(支持国密算法),需提前安装并配置开发环境。

skyksksksksks的博客 1487

跑Java -jar somefile.jar时会发生什么(一个)

最近阅读JVM源代码。一些想法写Blog分享。于是,他开了这么一个新课题。 第一篇文章取名字的时候让我很困惑,我代码的阅读是从Launcher開始入手的,也就是Java.exe(假设是windows平台的话)相应的相关代码,但我又不能取“JVM启动过程分析”之类的名字,由于从分析主流程的角度来讲还深不到这个层次。所以就暂且起了这么一个奇怪的名字。 这个系列假设能...

weixin_34040079的博客 138

【Unity3D】RTS Engine 笔记一

RTS Engine 中配置一个新场景, 初步认识GameManager、设置地形以及配置地形网格搜索

ViYeye的博客 1651

华为云CodeHub代码托管

什么是代码托管 代码托管(CodeHub)是面向软件开发者的基于Git的在线代码托管服务,是具备安全管控、成员/权限管理、分支保护/合并、在线编辑、统计服务等功能的云端代码仓库,旨在解决软件开发者在跨地域协同、多分支并发、代码版本管理、安全性等方面的问题。 代码托管具有以下特性 · 在线代码阅读、修改、提交,随时随地开发,不受地域限制。 · 在线分支管理,包含分支新建、切换、合并,实现多分支并行开发,效率高。 master分支:最为稳定,功能比较完整,随时可发布的代码。 develop分支:用于平时开

LUJINYUANA的博客 1万+

java 运行时 jar_运行Java -jar somefile.jar时发生了什么(二)

(6)Java.c中的LoadMainClass位置jdk/src/share/bin/java.c该方法负责载入main函数所在的类。该方法首先载入sun.launcher.LauncherHelper类,然后调用该类的checkAndLoadMain去找到main函数所在的类,相关代码例如以下。jclass cls = GetLauncherHelperClass(env);//这个函数载入了...

weixin_39915204的博客 146

zabbix监控深信服下一代防火墙配置

深信服下一代防火墙v8.0管理界面,zabbix,SNMP

weixin_43996471的博客 6873

运行Java -jar somefile.jar时发生了什么(二)

(6)Java.c中的LoadMainClass 位置jdk/src/share/bin/java.c 该方法负责载入main函数所在的类。该方法首先载入sun.launcher.LauncherHelper类,然后调用该类的checkAndLoadMain去找到main函数所在的类,相关代码例如以下。 jclass cls = GetLauncherHelperCl...

weixin_30295091的博客 130

SAP 财务快速记账之—G/L Item Fast Entry

SAP FICO 运维解决方案

lijinbao171022的博客 1647

Unreal Engine鸿蒙移植实战:环境配置、构建流程与性能优化指南

游戏引擎移植是跨平台开发中的关键技术环节,其核心原理在于通过适配目标操作系统的底层接口和工具链,实现同一套代码在不同硬件和软件环境下的高效运行。这项技术的价值在于最大化代码复用率,降低多平台维护成本,并能让应用快速触达新兴生态系统的用户。在移动游戏和XR应用领域,随着鸿蒙HarmonyOS生态的快速发展,将成熟的商业引擎如Unreal Engine迁移至此平台,成为开发者探索新市场机会的重要路径。本文聚焦于Unreal Engine项目向鸿蒙系统的移植实践,详细解析了从环境搭建、源码适配到构建打包的全链路流

weixin_29011395的博客 410

深入 GraalWasm 源码仓库:Truffle 版 WebAssembly 运行时的目录结构、构建、测试与跨仓库协作

本文以 GraalVM 仓库中 `wasm/` 子套件(GraalWasm)为核心,系统讲解其源码目录组织、mx 构建与测试命令、代码定位导航、以及 GraalWasm 与 Graal.js 之间的跨仓库边界约定。读完本文,你将能够基于当前仓库快速完成 GraalWasm 的构建、运行 `.wat`/`.wasm`/C 语言测试与 JMH 基准测试,并掌握修改字节码、解析器或解释器控制流时应遵循的

gitblog_01144的博客 359

Open Lovable 网站克隆AI工具超详细实战教程(含环境配置、排错与代码修改)

本教程面向有一定计算机基础的新手用户,提供一份全面、深入的 Open Lovable 使用指南。从开发环境搭建、API密钥获取、项目部署到网站克隆、代码下载、本地运行与二次开发,涵盖全流程细节与常见问题解决方案。通过本教程,新手可掌握如何利用AI驱动的Open Lovable工具,将任意目标网站智能复刻为结构清晰、可编辑的现代前端项目(React/Vite),实现快速原型开发与技术学习。

hy行者勇哥的博客 4963

parakeet-primeline-gguf 评测方法论全公开:862 条德语 WER 测试与 ß/ss 正字法细节

parakeet-primeline-gguf 是 NVIDIA parakeet-tdt-0.6b-v3 德语精调模型(parakeet-primeline)的 GGUF 量化版本,专为 [transcribe.cpp](https://link.gitcode.com/i/2e64bf4c8e28cb5283528c9b4f4012f0) 设计,支持 25 种语言的语音识别。本文完整公开其评测

gitblog_01195的博客 425

[网络安全提高篇] 一二〇.恶意软件动态分析经典沙箱Cape批量提取动态API特征

这是作者网络安全自学教程系列,主要是关于安全工具和实践操作的在线笔记,特分享出来与博友们学习,希望您喜欢,一起进步。前文详细介绍动态分析沙箱Cape的安装过程,其是一个开源的自动恶意软件分析系统,通过自动运行和分析恶意软件,全面分析和提取恶意软件的关键特征。然而,当样本数量增加时,单个样本分析会降低效率。这篇文章将讲解如何实现Cape沙箱的批量分析,通过调用Python脚本文件来实施批量处理,并将分析结果存储在指定位置,最后补充submit.py的参数及Python调用方式。基础性文章,希望对您有帮助!

杨秀璋的专栏 4122

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

工作中使用到的单词(软件开发)

1.エイリアス   alias 别名 powershell使用 get-help 命令时,会得到与此命令 相关(别名)的命令 2.プロキシ proxy 代 理 3.プロモート   promote 促进,提升   开发的系统新功能上线发布,有时会使用到这个词,比如 STプロモート 还有使用リリース这个词的。比如STリリース。个人认为两者含义相同。 4.見逃し み................................................................

sun0322 6万+

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

ZIP压缩全攻略:从右键创建到命令行、7-Zip进阶与报错排查

压缩文件是数字办公中基础且高频的需求,ZIP作为最通用、原生支持最广的格式,兼顾了兼容性与易用性。其核心设计包括集中目录区与独立文件压缩,实现了单文件提取和部分容错。本文从Windows、macOS、手机端创建ZIP的实操讲起,深入命令行zip命令、PowerShell、Python zipfile模块,并介绍7-Zip在密码加密、分卷压缩、批量处理方面的进阶用法,最后梳理乱码、损坏、密码遗忘等常见报错的排查思路,帮助用户从根源上理解并高效使用ZIP。

weixin_34166847的博客 279

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

linux命令详解及软件安装(持续更新)

linux解析 在java开发之路(javase、Mysql、前端(html、Css、Js)、JavaWeb、SSM(到这里很多人就开始找工作了)、Springboot、Vue、SpringCloud、MybatisPlus、Git…) 走到一定程度之后。 接下来再要遇到的技术(消息队列(kafka、RabbitMQ、RockeetMQ)、缓存(Redis)、搜索引擎(ES)、集群分布式(需要购买.....................

Ferao的博客 1万+
上一篇: Weka算法Classifier-meta-AdaBoostM1源码分析(二)
下一篇: 执行Java -jar somefile.jar时发生了什么(二)
ROger__Wong
博客等级 码龄14年 250粉丝 78原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值