从JDK源码级深入剖析main方法的运行机制
如果你是一名Java應(yīng)用開發(fā)工程師,你應(yīng)該對“public static void main(String[] args)”這段代碼再熟悉不過了,然而你是否了解main方法是如何調(diào)用的,為什么我們運行java.exe,就能啟動應(yīng)用程序?下面,讓我們來一探究竟吧!
首先,聊一聊,java.exe文件是怎么來的
如果你下載了OpenJDK源碼,在源碼目錄src\java.base\share\native\libjli目錄下有java.c這樣一個文件,java.exe文件是通過編譯java.c文件生成的可執(zhí)行文件。java.c文件是Java Runtime Environment(JRE)的一部分,它是用C語言編寫的,用于啟動Java應(yīng)用程序并運行Java字節(jié)碼。
其次,講一講,運行java.exe后發(fā)生了什么
在java.c文件當(dāng)中,有這樣一個方法:
/*
* 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虛擬機的入口點,負(fù)責(zé)解析命令行參數(shù)、加載Java應(yīng)用程序并啟動Java虛擬機。在JLI_Launch方法中,會解析命令行參數(shù),包括指定Java類路徑、指定JVM參數(shù)等,然后調(diào)用JVM的啟動函數(shù),啟動Java虛擬機并加載Java應(yīng)用程序。也就是說,當(dāng)你運行“java.exe YourClassName”這個命令時,調(diào)用的就是JLI_Launch這個方法。
接著,看一看,JLI_Launch這個方法做了哪些事情
我們進入方法內(nèi)部,我們看到方法的最后一行代碼:
return JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret);
該代碼作用是對Java虛擬機進行初始化,如果你現(xiàn)在是windows系統(tǒng)中運行java應(yīng)用程序,那么該方法的實現(xiàn)是在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);
}
我們繼續(xù)進入ContinueInNewThread這個方法,發(fā)現(xiàn)了
rslt = CallJavaMainInNewThread(threadStackSize, (void*)&args);
這段代碼,繼續(xù)進入CallJavaMainInNewThread,找到了這段代碼
rslt = JavaMain(args);
因此我們知道了:Java類中的main方法public static void main(String[] args),就是由java.c文件中JavaMain方法調(diào)用的。
接著,瞧一瞧,JavaMain這個方法是如何調(diào)用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);
//調(diào)用main函數(shù)
(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
...
}
這里可能就有讀者要問了,C程序是怎么調(diào)用Java程序的?
實際上,通過JNI(java本地接口,是Java Native Interface的縮寫)技術(shù)可以實現(xiàn)C語言調(diào)用Java,JNI是Java平臺提供的一種編程框架,用于實現(xiàn)Java應(yīng)用程序與本地(非Java)應(yīng)用程序之間的相互調(diào)用。JNI提供了一組規(guī)范和工具,使Java應(yīng)用程序能夠調(diào)用C、C++和其他本地語言編寫的代碼,反之亦然。通過JNI,Java程序員可以利用現(xiàn)有的本地代碼庫,并與其他本地應(yīng)用程序進行交互,從而擴展Java應(yīng)用程序的功能和性能。
最后,我們用流程圖總結(jié)一下
總結(jié)
以上是生活随笔為你收集整理的从JDK源码级深入剖析main方法的运行机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Desert King(最优比率生成树)
- 下一篇: 工业污水流量计在废水处理中的关键作用