jvm-demo 系列一:解析命令行工具类

本贴最后更新于 816 天前,其中的信息可能已经沧海桑田

参考资料:《深入理解 java 虚拟机》

《自己动手写 java 虚拟机》

zachaxy 手写 jvm 系列

先自己动手编写一个类似 java 命令行的工具,用它启动虚拟机。Java 虚拟机的工作是运行 Java 应用程序。和其他类型的应用程序一样,Java 应用程序也需要一个入口点,这个入口点就是我们熟知的 main()方法。如果一个类包含 main()方法,这个类就可以用来启动 Java 应用程序,我们把这个类叫作主类。最简单的 Java 程序是
只有一个 main()方法的类,如著名的 HelloWorld 程序。那么 Java 虚拟机如何知道我们要从哪个类启动应用程序呢?对此,Java 虚拟机规范没有明确规定。也就是说,是由虚拟机实现自行决定的。比如 Oracle 的 Java 虚拟机实现是通过 java 命令来启动的,主类名由命令行参数指定。java 命令有如下形式:

java [-options] class [args]

java [-options] -jar jarfile [args]

javaw [-options] class [args]

这里我们不先考虑完整的 java 命令用法,打算实现几个比较基础的命令

      java -version
      java -?
      java -help
      java -cp your/classpath yourClassName

先用一个结构体表示命令行

public class Cmd{
    Boolean helpFlag;//是否是help命令
    Boolean versionFlag;//是否是查看版本命令
    String cpOption;//classPath路径
    String  clazz;//
    String[]  args;//执行clazz文件需要的参数
}

先对输入的命令进行正则表达式处理,判断是否符合 java 命令用法,不符合直接返回错误。

public class CmdValidator {
    private static final Pattern CMD_PATTERN = Pattern.compile("^java\\s+(-version|-\\?|-help|-cp|-classpath)\\s*(.*)$");
     public  static  boolean isValidCmd(String cmdLine){
         Matcher matcher=CMD_PATTERN.matcher(cmdLine);
         return matcher.matches();
     }
}

一开始我是想去用 if,else 的逻辑去判断命令行处理,类似于这样

 public void parseCmd(String[] args){
       if("-help".equals(args[1]) || "-?".equals(args[1])){
           System.out.println("java help");
       }else if("-verson".equals(args[1])){
           System.out.println("java version");
       }else if("-cp".equals(args[1])){
           System.out.println("java  -cp");
           System.out.println(args[2]+"  "+args[3]);
       }

代码看起来太丑陋了,而且这种代码只是我们实现的命令少,实现的命令多就会非常冗杂,所以我们用责任链模式优化一下。

我们定义了一个抽象类 CommandHandler,它代表责任链中的一个处理步骤。每个具体的处理者类(如 HelpHandlerVersionHandlerClasspathHandler)都负责检查它是否可以处理给定的命令行参数。如果它不能处理,就将处理委托给责任链中的下一个处理者。

public abstract class CommandHandler {
    protected CommandHandler successor;

    public void setSuccessor(CommandHandler successor) {
        this.successor = successor;
    }

    public abstract void handleCommand(String[] args);
}

public class HelpHandler extends CommandHandler {
    @Override
    public void handleCommand(String[] args) {
        if ("-help".equals(args[1]) || "-?".equals(args[1])) {
            System.out.println("java help");
        } else if (successor != null) {
            successor.handleCommand(args);
        }
    }
}

public class VersionHandler extends CommandHandler {
    @Override
    public void handleCommand(String[] args) {
        if ("-version".equals(args[1])) {
            System.out.println("java version");
        } else if (successor != null) {
            successor.handleCommand(args);
        }
    }
}

public class ClassPathHandler extends CommadHandler{
    @Override
    public void handleCommand(String[] args) {
     if("-cp".equals(args[1])){
         System.out.println("successful");
         System.out.println("class文件的路径"+args[2]+"class文件"+args[3]+"交给下一节处理");
     } else if (successor != null) {
         successor.handleCommand(args);
     }
    }
}

public class Cmd {
    Boolean helpFlag;//是否是help命令
    Boolean versionFlag;//是否是查看版本命令
    String cpOption;//classPath路径
    String[]  args;//执行clazz文件需要的参数
    private CommandHandler handler;

   public  Cmd(String cmdLine){
         //解析命令行参数,以单个或者多个空格分开,这种方式目前不支持,因为如果输入的 路径名 中间有空格会导致下面解析失败
        if(!CmdValidator.isValidCmd(cmdLine)){
            System.out.println("Unrecognized option: -ewf\n" +
                    "Error: Could not create the Java Virtual Machine.\n" +
                    "Error: A fatal exception has occurred. Program will exit.");
            return;
        }
        //初始化责任链
        CommadHandler helpHandler=new HelperHandler();
        CommadHandler vesionHandler=new VersionHandler();
        CommadHandler classpathHandler=new ClassPathHandler();
        helpHandler.setSuccessor(vesionHandler);
        vesionHandler.setSuccessor(classpathHandler);
        handler=helpHandler;
        String[] args = cmdLine.trim().split("\\s+");
        parseCmd(args);
    }

    public void parseCmd(String[] args) {
        handler.handleCommand(args);
    }
}

Cmd 类中,我们初始化了责任链,然后调用 handler.handleCommand(args) 来开始处理命令行参数。

+------------------+          +------------------+
|   CommandHandler |          |     Cmd          |
+------------------+          +------------------+
| - successor      |          | - handler        |
+------------------+          +------------------+
       |                          |
       +--------------------------+
                          |
                 +------------------+
                 |  HelpHandler     |
                 +------------------+
                 |  handleCommand() |
                 +------------------+
                          |
                 +------------------+
                 |  VersionHandler  |
                 +------------------+
                 |  handleCommand() |
                 +------------------+
                          |
                 +------------------+
                 | ClasspathHandler |
                 +------------------+
                 |  handleCommand() |
                 +------------------+

这个逻辑图展示了这几个类之间的关系。CommandHandler 类是一个抽象类,它定义了一个 successor 属性,该属性表示责任链中的下一个处理者。具体的处理者类(HelpHandlerVersionHandlerClasspathHandler)继承自 CommandHandler 类,并实现了 handleCommand 方法来处理命令行参数。Cmd 类初始化了责任链,并调用责任链的第一个处理者(HelpHandler)来处理命令行参数。

责任链模式的使用让代码的扩展性变好了。

  • JVM

    JVM(Java Virtual Machine)Java 虚拟机是一个微型操作系统,有自己的硬件构架体系,还有相应的指令系统。能够识别 Java 独特的 .class 文件(字节码),能够将这些文件中的信息读取出来,使得 Java 程序只需要生成 Java 虚拟机上的字节码后就能在不同操作系统平台上进行运行。

    180 引用 • 120 回帖
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3202 引用 • 8217 回帖 • 1 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • Sublime

    Sublime Text 是一款可以用来写代码、写文章的文本编辑器。支持代码高亮、自动完成,还支持通过插件进行扩展。

    10 引用 • 5 回帖 • 1 关注
  • 区块链

    区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。所谓共识机制是区块链系统中实现不同节点之间建立信任、获取权益的数学算法 。

    92 引用 • 752 回帖 • 2 关注
  • Flume

    Flume 是一套分布式的、可靠的,可用于有效地收集、聚合和搬运大量日志数据的服务架构。

    9 引用 • 6 回帖 • 662 关注
  • Ant-Design

    Ant Design 是服务于企业级产品的设计体系,基于确定和自然的设计价值观上的模块化解决方案,让设计者和开发者专注于更好的用户体验。

    17 引用 • 23 回帖 • 3 关注
  • Visio
    1 引用 • 2 回帖 • 3 关注
  • Logseq

    Logseq 是一个隐私优先、开源的知识库工具。

    Logseq is a joyful, open-source outliner that works on top of local plain-text Markdown and Org-mode files. Use it to write, organize and share your thoughts, keep your to-do list, and build your own digital garden.

    7 引用 • 69 回帖 • 5 关注
  • 生活

    生活是指人类生存过程中的各项活动的总和,范畴较广,一般指为幸福的意义而存在。生活实际上是对人生的一种诠释。生活包括人类在社会中与自己息息相关的日常活动和心理影射。

    230 引用 • 1432 回帖 • 2 关注
  • flomo

    flomo 是新一代 「卡片笔记」 ,专注在碎片化时代,促进你的记录,帮你积累更多知识资产。

    6 引用 • 143 回帖
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 563 关注
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用 • 2 关注
  • OnlyOffice
    4 引用 • 20 关注
  • RabbitMQ

    RabbitMQ 是一个开源的 AMQP 实现,服务器端用 Erlang 语言编写,支持多种语言客户端,如:Python、Ruby、.NET、Java、C、PHP、ActionScript 等。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

    49 引用 • 60 回帖 • 354 关注
  • 资讯

    资讯是用户因为及时地获得它并利用它而能够在相对短的时间内给自己带来价值的信息,资讯有时效性和地域性。

    56 引用 • 85 回帖 • 1 关注
  • Outlook
    1 引用 • 5 回帖 • 3 关注
  • uTools

    uTools 是一个极简、插件化、跨平台的现代桌面软件。通过自由选配丰富的插件,打造你得心应手的工具集合。

    7 引用 • 28 回帖
  • 阿里云

    阿里云是阿里巴巴集团旗下公司,是全球领先的云计算及人工智能科技公司。提供云服务器、云数据库、云安全等云计算服务,以及大数据、人工智能服务、精准定制基于场景的行业解决方案。

    85 引用 • 324 回帖
  • JRebel

    JRebel 是一款 Java 虚拟机插件,它使得 Java 程序员能在不进行重部署的情况下,即时看到代码的改变对一个应用程序带来的影响。

    26 引用 • 78 回帖 • 683 关注
  • PHP

    PHP(Hypertext Preprocessor)是一种开源脚本语言。语法吸收了 C 语言、 Java 和 Perl 的特点,主要适用于 Web 开发领域,据说是世界上最好的编程语言。

    167 引用 • 408 回帖 • 482 关注
  • SQLite

    SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是全世界使用最为广泛的数据库引擎。

    4 引用 • 7 回帖
  • Dubbo

    Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,是 [阿里巴巴] SOA 服务化治理方案的核心框架,每天为 2,000+ 个服务提供 3,000,000,000+ 次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。

    60 引用 • 82 回帖 • 617 关注
  • RemNote
    2 引用 • 16 回帖 • 25 关注
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    10166 引用 • 46203 回帖 • 63 关注
  • Excel
    31 引用 • 28 回帖
  • Log4j

    Log4j 是 Apache 开源的一款使用广泛的 Java 日志组件。

    20 引用 • 18 回帖 • 37 关注
  • FFmpeg

    FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。

    23 引用 • 32 回帖 • 9 关注
  • SpaceVim

    SpaceVim 是一个社区驱动的模块化 vim/neovim 配置集合,以模块的方式组织管理插件以
    及相关配置,为不同的语言开发量身定制了相关的开发模块,该模块提供代码自动补全,
    语法检查、格式化、调试、REPL 等特性。用户仅需载入相关语言的模块即可得到一个开箱
    即用的 Vim-IDE。

    3 引用 • 31 回帖 • 112 关注
  • V2Ray
    1 引用 • 15 回帖 • 4 关注