180718-jar包執行傳參使用小結


logo

jar包執行時傳參的使用姿勢

雖說我們現在大多不太直接使用jar包運行方式,目前比較主流的是將自己的服務丟在某個容器中(如tomcat,jetty等)運行,比如我之前所屬的電商公司,就是將項目打包為war包,丟到tomcat容器中運行的

在使用SpringBoot時,可能會出現直接打包一個可執行的jar,然后運行,這種時候,通過java命令執行時,時可以傳參的,那么問題來了,main方法可以如何優雅的解析這些傳參呢?

I. 簡陋版本

最容易想到的,無非是自己直接解析main方法的傳參,如我們知道的main方法的一般寫法為

public static void main(String[] args) {
}

看到上面的寫法,很容易就可以猜到,傳入的參數最終都放到了args數組中,那么該怎么用就怎么用,一個hello world的實例如下

public static void main(String[] args) {
	System.out.println("hello " + args[0]);
}

測試如下:

image.png

看到這里,真心感覺沒有什么干貨,上面這些過於小白了吧,估計連入門都算不上,那么參數處理僅止於此么?

II. 進階版本

玩過shell的同學應該都知道man命令,可以用來查看很多shell命令的幫助,里面介紹了很多的shell命令的參數說明,而且這些參數一般有縮寫和全拼,而且有些參數可以帶傳值,有些並不需要,可以說shell命令的傳參方式,已經擁有自己獨立的一套規范了,而且用起來非常的爽

那么我們的jar包,能否支持這種傳參方式呢?

舉一個簡單的例子,上面的HelloWord接收一個簡單用戶名參數

  • 不傳入時,默認輸出 hello world
  • 短參方式: -n xxx
  • 長參方式: --name=xxx

僅僅支持這一個場景,需要自己來解析的話,就得寫一長串的代碼,好在這種需求已經有輪子了

1. commons-cli

首先引入依賴

<dependency>
    <groupId>commons-cli</groupId>
    <artifactId>commons-cli</artifactId>
    <version>1.3.1</version>
</dependency>

開始使用,官網已經給出了例子,完整的doc可以參考

2. 實例演示

下面結合我的一個項目,給出實際的使用方式

@Slf4j
public class AppLaunch {
    private static final String SOURCE_PATH = "./task-core/src/test/java/com/git/hui/task";
    private static final String TASK_ARG_LONG = "task";
    private static final String TASK_ARG_SHORT = "t";
    private static final String ARG_HELP_LONG = "help";
    private static final String ARG_HELP_SHORT = "h";
    private static volatile boolean run = true;


    private static void printHelp() {
        Options options = buildOptions();
        HelpFormatter helpFormatter = new HelpFormatter();
        helpFormatter.printHelp("java -jar ${jar} [options]", options);
    }

    private static Options buildOptions() {
        Options options = new Options();
        options.addOption(
                Option.builder(TASK_ARG_SHORT).argName(TASK_ARG_LONG).hasArg().longOpt(TASK_ARG_LONG).required(false)
                        .desc("choose task path, default [" + SOURCE_PATH + "]").build());
        options.addOption(Option.builder(ARG_HELP_SHORT).longOpt(ARG_HELP_LONG).desc("show command help").build());
        return options;
    }

    private static CommandLine parseArguments(String[] arguments) {
        Options options = buildOptions();
        CommandLine commandLine = null;
        try {
            commandLine = new DefaultParser().parse(options, arguments);
        } catch (ParseException e) {
            e.printStackTrace();
            System.exit(1);
        }

        if (commandLine.hasOption(ARG_HELP_LONG)) {
            printHelp();
            System.exit(0);
        }
        return commandLine;
    }


    public static void main(String[] args) throws InterruptedException {
        CommandLine commandLine = parseArguments(args);
        String scriptSource = commandLine.getOptionValue(TASK_ARG_LONG, SOURCE_PATH);
        System.out.println("script source: {}" + scriptSource);
        // ....
    }
}

對上面的使用姿勢進行簡單的說明,從邏輯上划分,可以分為下面幾塊

  • 定義傳參,包括參數說明,縮寫和全拼,是否有參數值,描述等
  • 解析傳參數組,將具體的傳參解析為CommandLine對象
  • 獲取參數,執行相應的業務邏輯

從源碼角度來看,沒什么復雜或者難以理解的地方,稍稍提一點,參數的定義,即buildOption方法中,上面指定了兩個參數 help, task, 其中一個要求有參數值,一個不需要參數值,下面實際演示如下

image.png

III. 其他

0. 相關信息

1. 一灰灰Bloghttps://liuyueyi.github.io/hexblog

一灰灰的個人博客,記錄所有學習和工作中的博文,歡迎大家前去逛逛

2. 聲明

盡信書則不如,已上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激

3. 掃描關注

QrCode


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM