[Java SE] 徹底搞懂Java程序的三大參數配置途徑:系統變量與JVM參數(VM Option)/環境變量/啓動程序參數args

0 序言

一次沒搞懂,處處受影響。這個問題屬於基礎問題,但又經常踩坑,不得不重視一下了。

1 Java程序動態參數的配置途徑:系統變量與JVM參數(VM Option) vs 環境變量 vs 啓動程序參數args

IDEA中的配置位置

參數 使用方式 示例 代碼獲取方式
系統屬性 由操作系統、JVM、應用程序主動設置 System.setProperties(Properties propes) / System.setProperties(String key,String value) / System.getProperties().load(String filename) / ... String value = System.getProperty(propertyName);
VM Options(JVM參數) 優先級高於系統變量。必須以-D-X-XX 開頭,每個參數用空格隔開 -Dvm.key=VmKey -Dvm.key2=VmKey2 String key = System.getProperty(vm.key);
Program Arguments(程序啓動參數) 每個參數用空格隔開 p.key=Program_Key p.name=ProgramName p.age=18 main(String[] args)
Environment Variable(環境變量) 我的電腦-屬性-高級環境設置-環境變量內配置系統屬性。其優先級低於 VM options ,即如果VM options 有一個變量和 Environment variable中的變量的key相同,則以VM options 中爲準, 以分號分割多個 env.key=env_james;server.servlet.context-path=/test;server.port=8080 String envKey = System.getenv(“env.key”);

2 工具類:SystemVariableTool

import cn.xx.bd.xx.common.debug.Print;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.DefaultApplicationArguments;
import org.springframework.util.ObjectUtils;

import java.util.*;

/**
 * @author johnny-zen
 * @version v1.0
 * @create-time 2023/6/9 9:57
 * @description 系統屬性讀取工具
 *  [VM options]
 *      VM options其實就是我們在程序中需要的運行時環境變量,它需要以-D或-X或-XX開頭,每個參數使用空格分隔
 *      使用最多的就是-Dkey=value設定系統屬性值,比如-Dspring.profiles.active=dev3
 *  [Program arguments]
 *      Program arguments爲我們傳入main方法的字符串數組args[],它通常以--開頭,如--spring.profiles.active=dev3
 *      等價於-Dspring.profiles.active=dev3如果同時存在,以Program arguments配置優先
 * @refrence-doc
 * @gpt-promt
 */
public class SystemVariableTool {
    private final static Logger logger = LoggerFactory.getLogger(SystemVariableTool.class);

    public static final String SYSTEM_PROPERTY_PARAM = "SYSTEM_PROPERTY";

    public static final String ENVIRONMENT_VARIABLE_PARAM = "ENVIRONMENT_VARIABLE";

    /** args **/
    public static final String ARGS_PARAM = "ARGS_PARAM";
    // 可選參數
    public static final String OPTION_ARG_PARAM = "OPTION_ARG_VARIABLE";
    // 非可選參數
    public static final String NON_OPTION_ARG_PARAM = "NON_OPTION_ARG_PARAM";

    private ApplicationArguments applicationArguments;

    public SystemVariableTool(ApplicationArguments applicationArguments){
        this.applicationArguments = applicationArguments;
    }

    /**
     * 讀取系統屬性
     * @param propertyName
     * @config-method 配置方法
     *  1 ) IDEA - (Select one Program) - Edit Configurations - VM Options - ( "-Dserver.port=8088" / "-Xmx239m" )
     * @sample
     * server.port
     * -----------------------------
     * java.version Java 運行時環境版本
     * java.vendor Java 運行時環境供應商
     * java.vendor.url Java 供應商的 URL
     * java.home Java 安裝目錄
     * java.vm.specification.version Java 虛擬機規範版本
     * java.vm.specification.vendor Java 虛擬機規範供應商
     * java.vm.specification.name Java 虛擬機規範名稱
     * java.vm.version Java 虛擬機實現版本
     * java.vm.vendor Java 虛擬機實現供應商
     * java.vm.name Java 虛擬機實現名稱
     * java.specification.version Java 運行時環境規範版本
     * java.specification.vendor Java 運行時環境規範供應商
     * java.specification.name Java 運行時環境規範名稱
     * java.class.version Java 類格式版本號
     * java.class.path Java 類路徑
     * java.library.path 加載庫時搜索的路徑列表
     * java.io.tmpdir 默認的臨時文件路徑
     * java.compiler 要使用的 JIT 編譯器的名稱
     * java.ext.dirs 一個或多個擴展目錄的路徑
     * os.name 操作系統的名稱
     * os.arch 操作系統的架構 例如: "amd64"
     * os.version 操作系統的版本 例如: "10.0"
     * file.separator 文件分隔符(在 UNIX 系統中是"/")
     * path.separator 路徑分隔符(在 UNIX 系統中是":")
     * line.separator 行分隔符(在 UNIX 系統中是"/n")
     * user.country 用戶所在國家
     * user.name 用戶的賬戶名稱
     * user.home 用戶的主目錄 例如: "C:\Users\Johnny"
     * user.dir 用戶的當前工作目錄 例如: "E:\source_code\BigData\bdp_common_data_service"
     * user.language 用戶當前的語言 例如: "zh"
     * user.timezone 用戶所在時區 例如: "Asia/Shanghai"
     * @return
     */
    public static String getSystemProperty(String propertyName){
        Map enviromentProperties = System.getProperties();
        return (String) enviromentProperties.get(propertyName);
    }

    /**
     * 讀取環境變量
     * @config-method 配置方式 :
     *  優先級 : 方式1 < 方式2
     *  1) My Computer - 屬性 - 高級系統設置 - 環境變量 - ...
     *  2) IDEA - (Select one Program) - Edit Configurations - Environment Variables - ( ENV_VAR="env-var-demo" server.port=8090 ...)
     *
     * @sample
     * USERPROFILE        :用戶目錄
     * USERDNSDOMAIN      :用戶域
     * PATHEXT            :可執行後綴
     * JAVA_HOME          :Java安裝目錄
     * TEMP               :用戶臨時文件目錄
     * SystemDrive        :系統盤符
     * ProgramFiles       :默認程序目錄
     * USERDOMAIN         :帳戶的域的名稱
     * ALLUSERSPROFILE    :用戶公共目錄
     * SESSIONNAME        :Session名稱
     * TMP                :臨時目錄
     * Path               :path環境變量
     * CLASSPATH          :classpath環境變量
     * PROCESSOR_ARCHITECTURE :處理器體系結構
     * OS                     :操作系統類型
     * PROCESSOR_LEVEL    :處理級別
     * COMPUTERNAME       :計算機名
     * Windir             :系統安裝目錄
     * SystemRoot         :系統啓動目錄
     * USERNAME           :用戶名
     * ComSpec            :命令行解釋器可執行程序的準確路徑
     * APPDATA            :應用程序數據目錄
     * @return
     */
    public static String getEnvironmentVariable(String variableName){
        Map enviromentProperties = System.getenv();
        return (String) enviromentProperties.get(variableName);
    }

    public Map<String, Object> getVariables(String variableName){
        Map<String, Object> resultMap = new HashMap<>();
        String systemProperty = getSystemProperty(variableName);
        resultMap.put(SYSTEM_PROPERTY_PARAM, systemProperty);

        String environmentVariable = getEnvironmentVariable(variableName);
        resultMap.put(ENVIRONMENT_VARIABLE_PARAM, environmentVariable);

        //解析 args
        String argsValue = null;
        String[] args = applicationArguments.getSourceArgs();
        if(!ObjectUtils.isEmpty(args)){
            for(int i = 0; i < args.length; i++){
                if(args[i].toLowerCase().contains(variableName.toLowerCase())){
                    argsValue = args[i];
                }
            }
        }
        resultMap.put(ARGS_PARAM, argsValue);
        /**
         * 解析選項參數
         * @description
         *  1. 不同框架 對 args 的解析策略均不同。例如 Flink 的 ParameterTool 與 SpringBoot 的 DefaultApplicationArguments,解析規則和解析結果有很大差異
         *  1. 基於 SpringBoot 的 ApplicationArguments 接口, DefaultApplicationArguments 。 如果是以”--“爲前綴,則判定爲選項參數;反之,被判定爲 非選項參數
         * @sample
         * [1] 選項參數的有效示例
         *  --foo
         *  --foo=
         *  --foo=""
         *  --foo=bar
         *  --foo="bar then baz"
         *  --foo=bar,baz,biz
         * [2] 選項參數的無效示例
         *  -foo
         *  --foo bar
         *  --foo = bar
         *  --foo=bar --foo=baz --foo=biz
         */
        List<String> optionArgs = applicationArguments.getOptionValues(variableName);// args = { "--foo="bar then baz" } , variableName = "foo" => optionArgs = {"bar then baz"}
        resultMap.put(OPTION_ARG_PARAM, optionArgs);

        List<String> allNonOptionArgs = applicationArguments.getNonOptionArgs();// { "server.port=8089" , "server.port=8090", "boo=bar,then,baz" , "foo=bar then baz" }
        List<String> nonOptionArgs = new ArrayList<>();
        for(int i=0;i<allNonOptionArgs.size();i++){
            if(allNonOptionArgs.get(i).toLowerCase().contains(variableName.toLowerCase())){
                nonOptionArgs.add( allNonOptionArgs.get(i) );
            }
        }
        resultMap.put(NON_OPTION_ARG_PARAM, nonOptionArgs);
        return resultMap;
    }

    public static void main(String[] args) {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        SystemVariableTool systemPropertiesUtil = new SystemVariableTool(applicationArguments);
        Map<String, Object> map = systemPropertiesUtil.getVariables("server.port");
        Print.print(map);
    }
}

X 參考文獻

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章