(6)Java.c中的LoadMainClass
位置jdk/src/share/bin/java.c
该方法负责加载main函数所在的类。该方法首先加载sun.launcher.LauncherHelper类,然后调用该类的checkAndLoadMain去找到main函数所在的类,相关代码如下。
jclass cls = GetLauncherHelperClass(env);//这个函数加载了sun.launcher.LauncherHelper类 NULL_CHECK0(cls); if (JLI_IsTraceLauncher()) { start = CounterGet(); } NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls,//找到方法id "checkAndLoadMain", "(ZILjava/lang/String;)Ljava/lang/Class;")); str = NewPlatformString(env, name); result = (*env)->CallStaticObjectMethod(env, cls, mid, USE_STDERR, mode, str);//调用这个静态方法
位置:jdk/src/share/bin/classes/sun/launcher/LauncherHelper.java
Java代码比较直观,我就直接写注释了
public static Class<?> checkAndLoadMain(boolean printToStderr, int mode, String what) { initOutput(printToStderr); // get the class name String cn = null; <pre name="code" class="java" style="font-size: 17.7777786254883px; line-height: 26px;">//这里判断mode是传入的class还是jar,对应命令行 java -jar xxx.jar 或者 java xxx.classswitch (mode) { case LM_CLASS: cn = what; break; case LM_JAR: cn = getMainClassFromJar(what);//这个函数实现是从Jar的mainFest文件里得到主类的名字 break; default: // should never happen throw new InternalError("" + mode + ": Unknown launch mode"); } cn = cn.replace(‘/‘, ‘.‘); Class<?> mainClass = null; try { mainClass = scloader.loadClass(cn);//委派给这个类加载器加载主类,加载器水太深,不在这里展开说了 } catch (NoClassDefFoundError | ClassNotFoundException cnfe) { if (System.getProperty("os.name", "").contains("OS X") && Normalizer.isNormalized(cn, Normalizer.Form.NFD)) { try { // On Mac OS X since all names with diacretic symbols are given as decomposed it // is possible that main class name comes incorrectly from the command line // and we have to re-compose it mainClass = scloader.loadClass(Normalizer.normalize(cn, Normalizer.Form.NFC)); } catch (NoClassDefFoundError | ClassNotFoundException cnfe1) { abort(cnfe, "java.launcher.cls.error1", cn); } } else { abort(cnfe, "java.launcher.cls.error1", cn); } } // set to mainClass appClass = mainClass; /* * Check if FXHelper can launch it using the FX launcher. In an FX app, * the main class may or may not have a main method, so do this before * validating the main class. */ if (mainClass.equals(FXHelper.class) || FXHelper.doesExtendFXApplication(mainClass)) { // Will abort() if there are problems with the FX runtime FXHelper.setFXLaunchParameters(what, mode); return FXHelper.class; } validateMainClass(mainClass);//这里做了验证,验证函数稍后分析。 return mainClass; }
static void validateMainClass(Class<?> mainClass) { Method mainMethod; try { mainMethod = mainClass.getMethod("main", String[].class);//看看是否存在如下签名的方法 main(String[] argvs) } catch (NoSuchMethodException nsme) { // invalid main or not FX application, abort with an error abort(null, "java.launcher.cls.error4", mainClass.getName(), FXHelper.JAVAFX_APPLICATION_CLASS_NAME); return; // Avoid compiler issues } int mod = mainMethod.getModifiers();//取得限定符 if (!Modifier.isStatic(mod)) {//如果不是static的则报错 abort(null, "java.launcher.cls.error2", "static", mainMethod.getDeclaringClass().getName()); } if (mainMethod.getReturnType() != java.lang.Void.TYPE) { abort(null, "java.launcher.cls.error3",//如果不是void的也报错 mainMethod.getDeclaringClass().getName()); } }
这两篇博客主要分析了执行java命令具体会发生一些什么事情,通过阅读代码可以了解到配置的环境变量如何起作用,jvm何时初始化,以及主类加载及验证过程。
本片博客起码还有以下几点没有深入的分析到:
jvm如何初始化。
env结构和vm结构的关系及实现。
scloader怎么作用。
LauncherHelper如何加载。
这些问题或许会在后面的博客进行分析。
执行Java -jar somefile.jar时发生了什么(二)
原文:http://blog.csdn.net/roger__wong/article/details/39972585