第二章 用Java实现JVM之命令行工具

发布于:2025-07-20 ⋅ 阅读:(20) ⋅ 点赞:(0)

用Java实现JVM目录

第零章 用Java实现JVM之随便说点什么
第一章 用Java实现JVM之JVM的准备知识
第二章 用Java实现JVM之命令行工具
第三章 用Java实现JVM之查找Class文件
第四章 用Java实现JVM之解析class文件
第五章 用Java实现JVM之运行时数据区
第六章 用Java实现JVM之指令集和解释器
第七章 用Java实现JVM之类和对象
第八章 用Java实现JVM之方法调用和返回
第九章 用Java实现JVM之数组和字符串
第十章 用Java实现JVM之本地方法调用
第十一章 用Java实现JVM之异常处理
第十二章 用Java实现JVM之结束



前言

    前边已经具体讨论过jvm的规范了,终于开始lu代码了,接下来就开始吧

在这里插入图片描述


    在了解过 JVM规范,就具备了实现 JVM 的前提,不过在实现 JVM 之前,还需要准备一些东西。这篇先来实现命令行工具

一、java命令

    不知道大家有没有这么个疑问:电脑是怎么知道程序的从哪里开始执行?要知道一个程序相关代码可能有几千,甚至上万行,并且没有什么顺序可言。既然如此,那就大伙儿一起规定一个入口吧,这就是main方法的由来。方法倒是确定了,但是像java这种面向对象的语言,可能有一大堆类,这么多个class文件,找个main方法,也非易事。那就进一步规定吧:

  • 从参数中获取
  • MANIFEST.MF文件中获取

这些就构成了java命令行体系:

在这里插入图片描述

java命令有三组参数组成:选项、主类名(或者JAR文件名)和main方法参数。选项由减号(–)开头。通常,第一个非选项参数给出主类的完全限定名(fully qualified class name)。但是如果用户提供了–jar选项,则第一个非选项参数表示JAR文件名,java命令必须从这个JAR文件中寻找主类。javaw命令和java命令几乎一样,唯一的差别在于,javaw命令不显示命令行窗口,因此特别适合用于启动GUI(图形用户界面)应用程序

    这样干巴巴的讲,还是有点抽象,举个例子吧。从参数中获取这种情况就不用说了,主类就就在命令行中。类似于:java -cp lib/*.jar com.hqd.A

    接下来看下–jar选项。相信大家或多或少都接触过SpringBoot项目,一般情况下,运行SpringBoot项目,都是使用如下命令:

java -jar app.jar

或者,需要指定些参数

java -jar app.jar --server.port=8081

还有就是指定堆内存大小

java -Xms256m -Xmx1g -Denv=dev -jar app.jar --server.port=9090

这就是使用–jar选项运行java程序,那么主类在哪里呢?这个在jar中的META-INF/MANIFEST.MF中可以找到答案:

在这里插入图片描述
咦?怎么是Main-Class: org.springframework.boot.loader.JarLauncher,这不对吧,其实这是Spring对其进行了进一步封装,不过这里是jvm的专场,不是Spring。就不在深入了

    java命令结构大致明白了,接着我们把目光转到选项上,选项也有值得说到的地方。大致可以分为两类:标准选项和非标准选项。标准选项比较稳定,不会轻易变动。非标准选项以-X开头,很有可能会在未来的版本中变化。非标准选项中有一部分是高级选项,以-XX开头

类别 参数 用途
标准参数 -version 输出版本信息,然后退出
标准参数 -? / -help 输出帮助信息,然后退出
标准参数 -cp / -classpath 指定用户类路径
标准参数 -D<property>=<value> 设置 Java 系统属性
非标准参数 -Xms<size> 设置初始堆空间大小
非标准参数 -Xmx<size> 设置最大堆空间大小
非标准参数 -Xss<size> 设置线程栈空间大小
高级参数 -XX:+UseG1GC 启用 G1 垃圾回收器
高级参数 -XX:+PrintGCDetails 输出 GC 详细日志
高级参数 -XX:MaxPermSize=<size> 设置永久代大小(仅限 JDK 8 及以前)

二、编写命令行工具

    了解完java命令,就可以准备撸代码了。写代码之前,先明确目标:只需实现主体部分就行了,-X这种就不需要

    好了,现在一切都确定好了。开始撸代码。解析命令行这种功能很常见,市面上早就有相关工具了,如:picocliJCommander。这里我们的目标是jvm,没必要重复造轮子。对比了下,最终选择picocli。技术也选型完毕,定一个实体类,用以包装解析出来的参数信息。CmdArgs代码如下:


@Data
public class CmdArgs {
    /**
     * 打印参数信息
     */
    @CommandLine.Option(names = {"-?", "-help"}, description = "print help message")
    private boolean helpFlag;
    /**
     * 打印版本信息
     */
    @CommandLine.Option(names = {"-v", "-version"}, description = "print jjvm version")
    private boolean versionFlag;
    /**
     * jvm参数
     */
    @CommandLine.Option(names = {"-cp", "-classpath"}, description = "print jjvm lib path")
    private String cpOption;
    /**
     * 主类路径
     */
    @CommandLine.Parameters(index = "0", description = "main class full path", arity = "0..1")
    private String mainClass;
    /**
     * 主类参数
     */
    @CommandLine.Parameters(index = "1..*", description = "main method args", arity = "0..1")
    private List<String> args;
}

实体类有了,接着就是把main(String[] args)中的参数封装实体类,方面操作,根据传递参数执行对应动作。CmdCommand代码如下:

public class CmdCommand {

    public CmdArgs parseCmd(String[] argv) {
        CmdArgs cmdArgs = new CmdArgs();
        CommandLine cmd = new CommandLine(cmdArgs);
        cmd.parseArgs(argv);
        if (ArrayUtils.isEmpty(argv)) {
            cmdArgs.setHelpFlag(true);
        }
        if (cmdArgs.isHelpFlag()) {
            cmd.usage(System.out);
        } else if (cmdArgs.isVersionFlag()) {
            System.out.println("jjvm version: " + Constant.JJVM_VERSION);
        } else {
            startJVM(cmdArgs);
        }
        return cmdArgs;
    }

    private void startJVM(CmdArgs cmdArgs) {
        System.out.println("classpath: " + cmdArgs.getCpOption());
        System.out.println("main class: " + cmdArgs.getMainClass());
        System.out.println("main method args: " + ArrayUtils.toString(cmdArgs.getArgs()));
    }
}

三、测试

    编写完代码,测试下看看有没有问题。新增CmdTest类,代码如下:

public class CmdTest {
    public static void main(String[] args) {
        CmdCommand cmdCommand = new CmdCommand();
        cmdCommand.parseCmd(args);
    }
}

再给idea配置点参数,help参数

在这里插入图片描述

测试结果如下:

在这里插入图片描述

version参数:

在这里插入图片描述

测试结果如下:

在这里插入图片描述

启动命令:

在这里插入图片描述

测试结果如下:

在这里插入图片描述


总结

    今天刚开始,就先拿个简单的下下菜,热热身,就这几行命令,没啥难度,就不在多说啥了。。。


网站公告

今日签到

点亮在社区的每一天
去签到