首页 > 编程语言 >从JDK源码级深入剖析main方法的运行机制

从JDK源码级深入剖析main方法的运行机制

时间:2023-06-11 18:55:58浏览次数:44  
标签:Java JDK int 应用程序 char 源码 java main

如果你是一名Java应用开发工程师,你应该对“public static void main(String[] args)”这段代码再熟悉不过了,然而你是否了解main方法是如何调用的,为什么我们运行java.exe,就能启动应用程序?下面,让我们来一探究竟吧!

首先,聊一聊,java.exe文件是怎么来的

如果你下载了OpenJDK源码,在源码目录src\java.base\share\native\libjli目录下有java.c这样一个文件,java.exe文件是通过编译java.c文件生成的可执行文件。java.c文件是Java Runtime Environment(JRE)的一部分,它是用C语言编写的,用于启动Java应用程序并运行Java字节码。

其次,讲一讲,运行java.exe后发生了什么

在java.c文件当中,有这样一个方法:

/*
 * Entry point.
 */
JNIEXPORT int JNICALL
JLI_Launch(int argc, char ** argv,              /* main argc, argv */
        int jargc, const char** jargv,          /* java args */
        int appclassc, const char** appclassv,  /* app classpath */
        const char* fullversion,                /* full version defined */
        const char* dotversion,                 /* UNUSED 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                               /* unused */
)

这个方法是Java虚拟机的入口点,负责解析命令行参数、加载Java应用程序并启动Java虚拟机。在JLI_Launch方法中,会解析命令行参数,包括指定Java类路径、指定JVM参数等,然后调用JVM的启动函数,启动Java虚拟机并加载Java应用程序。也就是说,当你运行“java.exe YourClassName”这个命令时,调用的就是JLI_Launch这个方法。

接着,看一看,JLI_Launch这个方法做了哪些事情

我们进入方法内部,我们看到方法的最后一行代码:

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

该代码作用是对Java虚拟机进行初始化,如果你现在是windows系统中运行java应用程序,那么该方法的实现是在src\java.base\windows\native\libjli\java_md.c这个文件中:

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);
}

我们继续进入ContinueInNewThread这个方法,发现了

rslt = CallJavaMainInNewThread(threadStackSize, (void*)&args);

这段代码,继续进入CallJavaMainInNewThread,找到了这段代码

rslt = JavaMain(args);

因此我们知道了:Java类中的main方法public static void main(String[] args),就是由java.c文件中JavaMain方法调用的。

接着,瞧一瞧,JavaMain这个方法是如何调用main方法的

上代码:

int JavaMain(void* _args)
{
    JavaMainArgs *args = (JavaMainArgs *)_args;
    ...
    //初始化Java虚拟机
    if (!InitializeJVM(&vm, &env, &ifn)) {
        JLI_ReportErrorMessage(JVM_ERROR1);
        exit(1);
    }
    ...
    //加载主运行类
    mainClass = LoadMainClass(env, mode, what);
    CHECK_EXCEPTION_NULL_LEAVE(mainClass);
    ...  
    //通过加载的主运行类,获取main方法
    mainID = (*env)->GetStaticMethodID(env, mainClass,"main","([Ljava/lang/String;)V");   
    CHECK_EXCEPTION_NULL_LEAVE(mainID);
    //调用main函数
    (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
    ...
}

这里可能就有读者要问了,C程序是怎么调用Java程序的?
实际上,通过JNI(java本地接口,是Java Native Interface的缩写)技术可以实现C语言调用Java,JNI是Java平台提供的一种编程框架,用于实现Java应用程序与本地(非Java)应用程序之间的相互调用。JNI提供了一组规范和工具,使Java应用程序能够调用C、C++和其他本地语言编写的代码,反之亦然。通过JNI,Java程序员可以利用现有的本地代码库,并与其他本地应用程序进行交互,从而扩展Java应用程序的功能和性能。

最后,我们用流程图总结一下

 

标签:Java,JDK,int,应用程序,char,源码,java,main
From: https://www.cnblogs.com/springmorning/p/17473385.html

相关文章

  • Python modbus_tk 库源码分析
    modbus_tk源代码分析前言modbus_tcp协议是工业项目中常见的一种基于TCP/IP协议的设备数据交互协议。作为TCP/IP协议的上层协议,modbus_tcp协议涉及到两个概念:client和server。但更标准的叫法应该是master和slave。Slave:TCP/IP协议中的server方Master:TCP/IP协......
  • spring-mvc3 源码分析
    1,进入sevlet的service方法publicvoidservice(ServletRequestreq,ServletResponseres)throwsServletException,IOException{HttpServletRequestrequest;HttpServletResponseresponse;try{request=(HttpServletRequest)req;......
  • CInternetSession(获取网页源码)
    CObject└CInternetSession使用类CInternetSession创建并初始化一个或多个同时的Internet会话。如果需要,还可描述与代理服务器的连接。如果Internet连接必须在应用过程中保持着,可创建一个类CWinApp的CInternetSession成员。一旦已建立起Internet会话,就可调用OpenUR......
  • React - 28 redux部分源码解析
    myRedux.jsimport_from'./assets/utils';/*实现redux的部分源码*/exportconstcreateStore=functioncreateStore(reducer){if(typeofreducer!=='function')thrownewError("Expectedtherootreducertobeafunction");......
  • VideoEye源码编译错误记录
    最近在研究雷神的开源项目VideoEye,但是下载编译时用VS2013和VS2015都出现一些报错。分析是因为雷神调试的环境是VS2010,现在使用新版本VS编译时存在不兼容的问题。网上查找各种信息,最终问题得以解决,于是乎记录一下。【背景】项目地址http://git.oschina.net/leixiaohua1020/Vid......
  • jvm简单介绍(JDK1.8)
     线程私有程序计数器主要有两个作用:字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。注意:程......
  • 获取微信小程序源码
    获取微信小程序源码的三种方法:一、使用adb连接手机获取小程序源码1、手机root环境下开启调试模式,手机通过USB数据线连接电脑查看设备adb.exedevices连接设备adb.execonnect10.10.10.1//ip为手机IP2、手机未root环境下adbusbadbdevicesadbtcpip8888//设置端口号888......
  • Go语言之gin框架源码学习
    Go语言之gin框架源码学习gin框架路由注册与路由匹配、中间件packagemainimport( "fmt" "github.com/gin-gonic/gin" "net/http")funcfunc1(c*gin.Context){ fmt.Println("func1")}funcfunc2(c*gin.Context){ fmt.Println("func2......
  • 数学老师从没这么教过,乘法竖式中进位可以是多位(附Python实现与测试源码)...
    大概十五年前,曾经写过一个C语言版本的类似代码。核心思想是:在乘法竖式计算过程中,每次的进位实际上是可以超过一位的,虽然老师从来没有这么教过。这样的操作在Python中是没有必要的,因为Python中的数字没有大小限制。但在C语言或其他静态类型语言中,由于整型变量能够表示的范围有限,所以......
  • 构建高效互联网医院系统:源码开发技巧
    目前来看,互联网医院系统源码的构建成为了医院信息化建设的一个重要方向。在构建高效互联网医院系统的过程中,源码开发技巧显得尤为重要。本篇文章,小编将为大家着重讲述一下,希望对您有一定的帮助。一、系统整体架构设计理论上来讲,整体架构的开发就是互联网医院系统的核心之一,在这个过......