System源码浅析- initializeSystemClass(initProperties)

前情提要

在前面已经介绍过 System与initializeSystemClass 在此不做过多解释,没有看到的希望去查看!
System源码浅析- initializeSystemClass(initProperties)
System源码浅析- initializeSystemClass(saveAndRemoveProperties)
System源码浅析- initializeSystemClass(setXXX0)
System源码浅析- initializeSystemClass(loadLibrary)
System源码浅析- initializeSystemClass(setup)
System源码浅析- initializeSystemClass( setJavaLangAccess)

System

描述

System 类包含几个有用的类字段和方法。它不能被实例化。
System 类提供的设施包括标准输入、标准输出和错误输出流;访问外部定义的属性和环境变量;
一种加载文件和库的方法;以及一种用于快速复制数组的一部分的实用方法。

initializeSystemClass

描述

// VM 可能会在“props”初始化期间调用 JNU_NewStringPlatform() 来设置那些编码
// 敏感属性(user.home、user.name、boot.class.path 等),
// 在这些属性中它可能需要通过 System.getProperty() 访问,
// 在初始化的早期阶段已经初始化(放入“props”)的相关系统编码属性。
// 因此,请确保“props”在初始化的一开始就可用,并且所有系统属性都可以直接放入其中。
     /**
     * 初始化系统类。在线程初始化后调用。
     */
    private static void initializeSystemClass() {

        // VM 可能会在“props”初始化期间调用 JNU_NewStringPlatform() 来设置那些编码
        // 敏感属性(user.home、user.name、boot.class.path 等),
        // 在这些属性中它可能需要通过 System.getProperty() 访问,
        // 在初始化的早期阶段已经初始化(放入“props”)的相关系统编码属性。
        // 因此,请确保“props”在初始化的一开始就可用,并且所有系统属性都可以直接放入其中。
        props = new Properties();
        initProperties(props);  // initialized by the VM

        // 某些系统配置可能由 VM 选项控制,例如用于支持自动装箱的对象标识语义的最大直接内存量和整数缓存大小。
        // 通常,库将从 VM 设置的属性中获取这些值。如果属性仅供内部实现使用,
        // 则应从系统属性中删除这些属性。
        //
        // 例如,参见 java.lang.Integer.IntegerCache 和 sun.misc.VM.saveAndRemoveProperties 方法。
        //
        // 保存只能由内部实现访问的系统属性对象的私有副本。删除某些不打算供公众访问的系统属性。
        sun.misc.VM.saveAndRemoveProperties(props);


        lineSeparator = props.getProperty("line.separator");
        sun.misc.Version.init();
        // 文件流
        FileInputStream fdIn = new FileInputStream(FileDescriptor.in);
        FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
        FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);
        setIn0(new BufferedInputStream(fdIn));
        setOut0(newPrintStream(fdOut, props.getProperty("sun.stdout.encoding")));
        setErr0(newPrintStream(fdErr, props.getProperty("sun.stderr.encoding")));

        // 现在加载 zip 库,以防止 java.util.zip.ZipFile 稍后尝试使用自身加载此库。
        loadLibrary("zip");

        // 为 HUP、TERM 和 INT(如果可用)设置 Java 信号处理程序。
        Terminator.setup();

        // 初始化需要为类库设置的任何其他操作系统设置。
        // 目前,除了在使用 java.io 类之前设置了进程范围的错误模式的 Windows 之外,
        // 这在任何地方都是无操作的。
        sun.misc.VM.initializeOSEnvironment();

        // 主线程不像其他线程那样添加到它的线程组中;我们必须在这里自己做。
        Thread current = Thread.currentThread();
        current.getThreadGroup().add(current);

        // 注册共享秘密
        setJavaLangAccess();

        // 在初始化期间调用的子系统可以调用 sun.misc.VM.isBooted() 以避免执行应该等到应用程序类加载器设置完成的事情。
        // 重要提示:确保这仍然是最后的初始化操作!
        sun.misc.VM.booted();
    }

initProperties

private static native Properties initProperties(Properties props);

之后查看native源码

typedef struct {
    char *os_name;
    char *os_version;
    char *os_arch;

#ifdef JDK_ARCH_ABI_PROP_NAME
    char *sun_arch_abi;
#endif

    nchar *tmp_dir;
    nchar *font_dir;
    nchar *user_dir;

    char *file_separator;
    char *path_separator;
    char *line_separator;

    nchar *user_name;
    nchar *user_home;

    char *language;
    char *format_language;
    char *display_language;
    char *script;
    char *format_script;
    char *display_script;
    char *country;
    char *format_country;
    char *display_country;
    char *variant;
    char *format_variant;
    char *display_variant;
    char *encoding;
    char *sun_jnu_encoding;
    char *sun_stdout_encoding;
    char *sun_stderr_encoding;
    char *timezone;

    char *printerJob;
    char *graphics_env;
    char *awt_toolkit;

    char *unicode_encoding;     /* The default endianness of unicode
                                    i.e. UnicodeBig or UnicodeLittle   */

    const char *cpu_isalist;    /* list of supported instruction sets */

    char *cpu_endian;           /* endianness of platform */

    char *data_model;           /* 32 or 64 bit data model */

    char *patch_level;          /* patches/service packs installed */

    char *desktop;              /* Desktop name. */

#ifdef MACOSX
    // These are for proxy-related information.
    // Note that if these platform-specific extensions get out of hand we should make a new
    // structure for them and #include it here.
    int httpProxyEnabled;
    char *httpHost;
    char *httpPort;

    int httpsProxyEnabled;
    char *httpsHost;
    char *httpsPort;

    int ftpProxyEnabled;
    char *ftpHost;
    char *ftpPort;

    int socksProxyEnabled;
    char *socksHost;
    char *socksPort;

    int gopherProxyEnabled;
    char *gopherHost;
    char *gopherPort;

    char *exceptionList;

    char *awt_headless;  /* java.awt.headless setting, if NULL (default) will not be set */
#endif

} java_props_t;
struct JNIEnv_ {
    ....
}
typedef JNIEnv_ JNIEnv;

Java_java_lang_System_initProperties(JNIEnv *env, jclass cla, jobject props)
{
    char buf[128];
    java_props_t *sprops;
    jmethodID putID, removeID, getPropID;
    jobject ret = NULL;
    jstring jVMVal = NULL;
    // 获取Java 配置环境 里面主要是通过 各种预定义的宏区分不同的操作系统,之后进行对应的编译,获取环境设置 java_props_t的属性
    sprops = GetJavaProperties(env);
    CHECK_NULL_RETURN(sprops, NULL);
    /**
     #define JNICALL __stdcall c++ windows api 系统调用
     
     jmethodID (JNICALL *GetMethodID)
      (JNIEnv *env, jclass clazz, const char *name, const char *sig);
      
     jmethodID GetMethodID(jclass clazz, const char *name,
                          const char *sig) {
        return functions->GetMethodID(this,clazz,name,sig);
    }
    
    jclass (JNICALL *GetObjectClass)
      (JNIEnv *env, jobject obj);
      
     jclass GetObjectClass(jobject obj) {
        return functions->GetObjectClass(this,obj);
    }
    */
    putID = (*env)->GetMethodID(env,
                                (*env)->GetObjectClass(env, props),
                                "put",
            "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
    // 检查是否为null
    
/**
  define CHECK_NULL_RETURN(x, y)                 \
    do {                                        \
        if ((x) == NULL) {                      \
            return (y);                         \
        }                                       \
    } while (0)             
    */
    CHECK_NULL_RETURN(putID, NULL);

    removeID = (*env)->GetMethodID(env,
                                   (*env)->GetObjectClass(env, props),
                                   "remove",
            "(Ljava/lang/Object;)Ljava/lang/Object;");
    CHECK_NULL_RETURN(removeID, NULL);

    getPropID = (*env)->GetMethodID(env,
                                    (*env)->GetObjectClass(env, props),
                                    "getProperty",
            "(Ljava/lang/String;)Ljava/lang/String;");
    CHECK_NULL_RETURN(getPropID, NULL);
    
    /**
    #define PUTPROP(props, key, val)                                     \
    if (1) {                                                         \
        jstring jkey, jval;                                          \
        jobject r; 
        ======
        jstring NewStringUTF(const char *utf) {
        	return functions->NewStringUTF(this,utf);
    	}
    	=====
        jkey = (*env)->NewStringUTF(env, key);                       \
        if (jkey == NULL) return NULL;                               \
        jval = (*env)->NewStringUTF(env, val);                       \
        if (jval == NULL) return NULL;                               \
        r = (*env)->CallObjectMethod(env, props, putID, jkey, jval); \
        if ((*env)->ExceptionOccurred(env)) return NULL;             \
        (*env)->DeleteLocalRef(env, jkey);                           \
        (*env)->DeleteLocalRef(env, jval);                           \
        (*env)->DeleteLocalRef(env, r);                              \
    } else ((void) 0)
    */
    PUTPROP(props, "java.specification.version",
            JDK_MAJOR_VERSION "." JDK_MINOR_VERSION);
    PUTPROP(props, "java.specification.name",
            "Java Platform API Specification");
    PUTPROP(props, "java.specification.vendor",
            JAVA_SPECIFICATION_VENDOR);

    PUTPROP(props, "java.version", RELEASE);
    PUTPROP(props, "java.vendor", VENDOR);
    PUTPROP(props, "java.vendor.url", VENDOR_URL);
    PUTPROP(props, "java.vendor.url.bug", VENDOR_URL_BUG);

    jio_snprintf(buf, sizeof(buf), "%d.%d", JAVA_MAX_SUPPORTED_VERSION,
                                            JAVA_MAX_SUPPORTED_MINOR_VERSION);
    PUTPROP(props, "java.class.version", buf);

    if (sprops->awt_toolkit) {
        PUTPROP(props, "awt.toolkit", sprops->awt_toolkit);
    }
    ....
    /*
     * unset "user.language", "user.script", "user.country", and "user.variant"
     * in order to tell whether the command line option "-DXXXX=YYYY" is
     * specified or not.  They will be reset in fillI18nProps() below.
     取消设置“user.language”、“user.script”、“user.country”和“user.variant”,以判断是否指定了命令行选项“-DXXXX=YYYY”。它们将在下面的 		      fillI18nProps() 中重置
    */
    ==========
        #define REMOVEPROP(props, key)                                    \
    if (1) {                                                      \
        jstring jkey;                                             \
        jobject r;                                                \
        jkey = JNU_NewStringPlatform(env, key);                   \
        if (jkey == NULL) return NULL;                            \
        r = (*env)->CallObjectMethod(env, props, removeID, jkey); \
        if ((*env)->ExceptionOccurred(env)) return NULL;          \
        (*env)->DeleteLocalRef(env, jkey);                        \
        (*env)->DeleteLocalRef(env, r);                           \
    } else ((void) 0)
    ==========
    REMOVEPROP(props, "user.language");
    REMOVEPROP(props, "user.script");
    REMOVEPROP(props, "user.country");
    REMOVEPROP(props, "user.variant");
    REMOVEPROP(props, "file.encoding");
    // jvm 初始化
   ret = JVM_InitProperties(env, props);
    // 检查兼容性标志
    ...

JVM_InitProperties

通过宏进行对应的赋值,具体看下面的源码。

JVM_ENTRY(jobject, JVM_InitProperties(JNIEnv *env, jobject properties))
    // JVM 函数的包装器
  JVMWrapper("JVM_InitProperties");
	// 资源标记在调用析构函数时释放所有在构造后分配的资源。通常用作局部变量
	// 里面大致是通过各种预定义的宏对应初始化 ResourceMark中的属性
  ResourceMark rm;

  Handle props(THREAD, JNIHandles::resolve_non_null(properties));

  // 系统属性列表包括通过 -D 选项设置的用户和 jvm 系统特定的属性。
  for (SystemProperty* p = Arguments::system_properties(); p != NULL; p = p->next()) {
    PUTPROP(props, p->key(), p->value());
  }

  // 将 -XX:MaxDirectMemorySize= 命令行标志转换为 sun.nio.MaxDirectMemorySize 属性。
  //在设置用户属性后执行此操作,以防止人们按照要求使用 -D 选项设置值。
  {
    if (FLAG_IS_DEFAULT(MaxDirectMemorySize)) {
      PUTPROP(props, "sun.nio.MaxDirectMemorySize", "-1");
    } else {
      char as_chars[256];
      jio_snprintf(as_chars, sizeof(as_chars), UINTX_FORMAT, MaxDirectMemorySize);
      PUTPROP(props, "sun.nio.MaxDirectMemorySize", as_chars);
    }
  }

  // JVM 监控和管理支持 添加 sun.management.compiler 属性作为编译器的名称
  {
#undef CSIZE
#if defined(_LP64) || defined(_WIN64)
  #define CSIZE "64-Bit "
#else
  #define CSIZE
#endif // 64bit
#ifdef TIERED
    const char* compiler_name = "HotSpot " CSIZE "Tiered Compilers";
#else
#if defined(COMPILER1)
    const char* compiler_name = "HotSpot " CSIZE "Client Compiler";
#elif defined(COMPILER2)
    const char* compiler_name = "HotSpot " CSIZE "Server Compiler";
#else
    const char* compiler_name = "";
#endif // compilers
#endif // TIERED

    if (*compiler_name != '\0' &&
        (Arguments::mode() != Arguments::_int)) {
      PUTPROP(props, "sun.management.compiler", compiler_name);
    }
  }

  const char* enableSharedLookupCache = "false";
#if INCLUDE_CDS
  if (ClassLoaderExt::is_lookup_cache_enabled()) {
    enableSharedLookupCache = "true";
  }
#endif
  PUTPROP(props, "sun.cds.enableSharedLookupCache", enableSharedLookupCache);

  return properties;
JVM_END