3

JCommander:Java外部参数解析利器

 2 years ago
source link: http://kangkona.github.io/jcommander-using-example/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

JCommander:Java外部参数解析利器

13/Mar 2015

最近需要把项目交给别人进行运维,为了不让接手之人涉及太多繁琐细节,我把一些定义在final类中的不可变量抽取出来,把项目变成可外部配置的。用配置文件可以达到这个目的,但由于配置之间有相互依赖关系,比如:

public static boolean local = false;
public static String host =  (local) ? "127.0.0.1" : "172.16.3.142";
public static int port = (local) ? 6379 : 6380; 

原本只需要改变local, 用配置文件的话与local值有依赖关系的地方都要面临修改。

后来打算用命令行参数实现可外部动态配置,如果自己动手实现完善的命令行参数解析,可不是一项little job。 比较了几款开源的工具,还是选择了JCommander。主要原因是被它官网的slogan打动了:

Because life is too short to parse command line parameters.

项目是maven构建的,使用JCommander的方式十分简单:

<dependency>
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
</dependency>

使用JCommander的方式也很简单,给需要外部传参的变量加Parameter标注:

 @Parameter(names = { "-topologyName"}, description = "Topology name.")
 private static String TOP_NAME = "sz-train";

一般类型参数后面都要跟值,JCommander会根据对应变量做类型检查和转换,不合法时会抛出异常错误。

boolean类型有点特殊,后面不需要跟一个值,输入-local之后,local值即为true:

@Parameter(names = { "-local"}, description = "Local model, default cluster Model.")
public static boolean LOCAL_MODE = false;

如果一个boolean变量的默认值为true,而想通过参数设置为false,可以指定元数:

@Parameter(names = { "-log", "-verbose"}, description = " Wheather to write system log.", arity = 1)
public static boolean LOG = true;

默认情况下,参数是可选的,如果要求必须指定参数,可以设置required:

@Parameter(names = "-operator", required = true)
private String operator;

有时仅仅依靠JCommander的类型检查还不够,还需要自定义检查器提前发现不合法的输入:

@Parameter(names = { "-redisPort"}, description = "Redis port.", validateWith = PortValidator.class)
public static int REDIS_PORT=(LOCAL_MODE) ? 6379:6380;

public static class PortValidator implements IParameterValidator {
           public void validate(String name, String value)
            throws ParameterException {
          Pattern pattern = Pattern.compile("[1-9]\\d*");
          Matcher matcher = pattern.matcher(value);
          if (matcher.matches()) {
              int n = Integer.parseInt(value);
              if (n < 65536) {
                  return;
              }
          }
          throw new ParameterException("Parameter " + name 
                    + " should be a number(0~65535) (found " + value +")");
        }
      }

如果是一个写日志的目录,可以提前发现该目录是否可写,这是配置文件无法做到的:

@Parameter(names = { "-logDir"}, description = "Dir to write log file.", 
                                          validateWith = DirValidator.class)
public static String LOG_DIR = "/logs/your_project/"; 

public static class DirValidator implements IParameterValidator {
           public void validate(String name, String value)
            throws ParameterException {
            File file = new File(value);
            if (!file.isDirectory() || !file.canWrite()) {
                  throw new ParameterException("Parameter " + name 
                         + " should be a writable folder(found " + value +")");
                  }
            }
      }

对于IP地址,不仅可以通过正则表达式进行匹配,还可以进行简单的网络连通性探测等。相比基于文本的配置文件,JCommander显示出了强大的优势。

但更多的项目可能还是更适合用配置文件的方式进行外部配置,如果配置文件如果可以吸收JCommander的特点,那就perfect了。我理想中的配置文件应该有如下特性:
- 配置文件本身是programmable
- 可以进行上下文联系
- 自动类型检查和转换
- 可以自定义语义检查器
- 所使用的弱语言可以方便嵌入

Tags// java,
More Reading
Newer// PL Meets AI

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK