Java Runtime的使用详解

目录
  • 前言
  • 1. shutdownhook
  • 2. exec执行
    • 2.1 常规命令执行
    • 2.2 管道符
    • 2.3源码分析
  • 3. 总结

前言

最近做项目框架,需要在框架结束的时候,关闭服务器连接,清除部分框架运行lock文件,这里就想到了shutdownhook,顺便学了学Runtime的使用

1. shutdownhook

demo示例,证明在程序正常结束的时候会调用,如果kill -9 那肯定就不会调用了

public class ShutdownHookTest {
    public static void main(String[] args) {
        System.out.println("==============application start================");

        Runtime.getRuntime().addShutdownHook(new Thread(()->{
            System.out.println("--------------hook 1----------------");
        }));
        Runtime.getRuntime().addShutdownHook(new Thread(()->{
            System.out.println("--------------hook 2----------------");
        }));

        System.out.println("==============application end================");
    }
}

正常运行结束,结果如下

==============application start================
==============application end================
--------------hook 1----------------
--------------hook 2----------------

Process finished with exit code 0

如果暂停,点击下图左下角的正方形红图标,停止正在运行的应用

结果如下,shutdownhook已执行。

shutdownhook可以处理程序正常结束的时候,删除文件,关闭连接等

2. exec执行

2.1 常规命令执行

demo示例如下,比如ls

public class ShutdownHookTest {
    public static void main(String[] args) throws InterruptedException, IOException {
        Process process = Runtime.getRuntime().exec("ls");
        try (InputStream fis = process.getInputStream();
             InputStreamReader isr = new InputStreamReader(fis);
             BufferedReader br = new BufferedReader(isr)) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        }
    }
}

结果如下

而正常执行结果

但是这个方法有远程执行风险,即在浏览器端通过这个方法执行特定指令,比如执行rm -rf *,结果就很……

2.2 管道符

但是遇见管道符之后就会失效,什么办法解决,sh -c,但是不能直接用,否则获取到的是TTY窗口信息

    public static void main(String[] args) throws IOException {
        Process process = Runtime.getRuntime().exec("sh -c ps aux|grep java");
        try (InputStream fis = process.getInputStream();
             InputStreamReader isr = new InputStreamReader(fis);
             BufferedReader br = new BufferedReader(isr)) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        }
    }

结果

sh -c的参数要分离,不然runtime会认为是一个参数

2.3源码分析

跟踪代码,使用ProcessImpl来执行指令

    public Process exec(String[] cmdarray, String[] envp, File dir)
        throws IOException {
        return new ProcessBuilder(cmdarray)
            .environment(envp)
            .directory(dir)
            .start();
    }

ProcessBuilder

// Only for use by ProcessBuilder.start()
    static Process start(String[] cmdarray,
                         java.util.Map<String,String> environment,
                         String dir,
                         ProcessBuilder.Redirect[] redirects,
                         boolean redirectErrorStream)
        throws IOException
    {
        assert cmdarray != null && cmdarray.length > 0;

        // Convert arguments to a contiguous block; it's easier to do
        // memory management in Java than in C.
        byte[][] args = new byte[cmdarray.length-1][];
        int size = args.length; // For added NUL bytes
        for (int i = 0; i < args.length; i++) {
            args[i] = cmdarray[i+1].getBytes();
            size += args[i].length;
        }
        byte[] argBlock = new byte[size];
        int i = 0;
        for (byte[] arg : args) {
            System.arraycopy(arg, 0, argBlock, i, arg.length);
            i += arg.length + 1;
            // No need to write NUL bytes explicitly
        }

        int[] envc = new int[1];
        byte[] envBlock = ProcessEnvironment.toEnvironmentBlock(environment, envc);
        int[] std_fds;
        FileInputStream  f0 = null;
        FileOutputStream f1 = null;
        FileOutputStream f2 = null;

        try {
            if (redirects == null) {
                std_fds = new int[] { -1, -1, -1 };
            } else {
                std_fds = new int[3];

                if (redirects[0] == Redirect.PIPE)
                    std_fds[0] = -1;
                else if (redirects[0] == Redirect.INHERIT)
                    std_fds[0] = 0;
                else {
                    f0 = new FileInputStream(redirects[0].file());
                    std_fds[0] = fdAccess.get(f0.getFD());
                }

                if (redirects[1] == Redirect.PIPE)
                    std_fds[1] = -1;
                else if (redirects[1] == Redirect.INHERIT)
                    std_fds[1] = 1;
                else {
                    f1 = new FileOutputStream(redirects[1].file(),
                                              redirects[1].append());
                    std_fds[1] = fdAccess.get(f1.getFD());
                }

                if (redirects[2] == Redirect.PIPE)
                    std_fds[2] = -1;
                else if (redirects[2] == Redirect.INHERIT)
                    std_fds[2] = 2;
                else {
                    f2 = new FileOutputStream(redirects[2].file(),
                                              redirects[2].append());
                    std_fds[2] = fdAccess.get(f2.getFD());
                }
            }

        return new UNIXProcess
            (toCString(cmdarray[0]),
             argBlock, args.length,
             envBlock, envc[0],
             toCString(dir),
                 std_fds,
             redirectErrorStream);
        } finally {
            // In theory, close() can throw IOException
            // (although it is rather unlikely to happen here)
            try { if (f0 != null) f0.close(); }
            finally {
                try { if (f1 != null) f1.close(); }
                finally { if (f2 != null) f2.close(); }
            }
        }
    }

new UNIXProcess 环境


/**
 * java.lang.Process subclass in the UNIX environment.
 *
 * @author Mario Wolczko and Ross Knippel.
 * @author Konstantin Kladko (ported to Linux and Bsd)
 * @author Martin Buchholz
 * @author Volker Simonis (ported to AIX)
 */
final class UNIXProcess extends Process {

3. 总结

Runtime用处非常多,偏底层

比如gc调用

加载jar文件

Runtime功能强大,但需要合理利用,很多攻击是通过Runtime执行的漏洞

但是使用shutdownhook还是很方便的,用来做停止任务的后续处理。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • java.lang.Runtime.exec() Payload知识点详解

    有时,通过Runtime.getRuntime().exec()执行命令的有效负载有时会失败.使用Web Shell,反序列化利用或通过其他媒介时,可能会发生这种情况. 有时这是因为重定向和管道字符的使用在启动过程的上下文中没有意义.例如,在shell中执行ls> dir_listing会将当前目录的列表输出到名为dir_listing的文件中.但是在exec()函数的上下文中,该命令将被解释为获取>和dir_listing目录的列表. 有时,StringTokenizer类会破坏其中包含空格

  • java Runtime如何执行多条命令

    目录 java Runtime如何执行多条命令 Runtime.getRuntime().exec 执行多条 java Runtime如何执行多条命令 使用 && 分隔命令 public static void cmd() { String ls = " cd /home/ && dir "; Process process = null; String cmd = getOsCmd()+ ls; try { process = Runtime.getR

  • Java Process与Runtime()的使用及调用cmd命令阻塞的解决方案

    Java Process与Runtime()使用 java调用cmd执行bat文件有时会出现卡死的现象,当时感觉很迷惑,后来查资料,本来一般都是这样来调用程序并获取进程的输出流的,但是我在windows上执行这样的调用的时候却总是在while那里被堵塞了,结果造成ffmpeg程序在执行了一会后不再执行,这里从官方的参考文档中我们可以看到这是由于缓冲区的问题,由于java进程没有清空ffmpeg程序写到缓冲区的内容,结果导致ffmpeg程序一直在等待. 在网上也查找了很多这样的问题,不过说的都是使

  • 调用java.lang.Runtime.exec的正确姿势分享

    目录 调用java.lang.Runtime.exec的正确姿势 两种方法 小结一下 Java Runtime.exec()注意事项 1.Runtime.exec() 有四种调用方法 2.得到程序执行返回值, 0为success 3.得到程序执行的结果或错误信息 4.Runtime.exec() 调用java.lang.Runtime.exec的正确姿势 今天写一个用到编译的程序,遇到了问题. 在调用 runtime.exec("javac HelloWorld.java"); 运行完

  • java使用Runtime执行系统命令遇到的问题

    目录 使用Runtime执行系统命令遇到的问题 参数含义 下面是实现代码 java Runtime.exec() 执行 举个例子 使用Runtime执行系统命令遇到的问题 java执行系统命令的工具,Runtime.getRuntime().exec(),这个工具里面的坑还是不少的,大部分网上已经分析了,我遇到一个没有在网上找到的. 首先说一下这个坑,在command中如果参数的内容中有空格.tab.换行符.回车符,就会执行失败,例如:grep "abc def" -r -n ./这是

  • java.lang.Runtime.exec的左膀右臂:流输入和流读取详解

    目录 什么是java.lang.Runtime 什么是java.lang.Process 具体做法 Runtime.exec 陷阱 IllegalThreadStateException 为什么Runtime.exec()挂起 在java.lang.Runtime.exec的使用中,我们经常会用到将重定向命令执行的输入/结果或者将错误信息读取出来. 那么,在使用过程中,我们如何正确的使用呢? 什么是java.lang.Runtime 首先我们要明确一点,什么是Java.lang.Runtime?

  • Java Runtime的使用详解

    目录 前言 1. shutdownhook 2. exec执行 2.1 常规命令执行 2.2 管道符 2.3源码分析 3. 总结 前言 最近做项目框架,需要在框架结束的时候,关闭服务器连接,清除部分框架运行lock文件,这里就想到了shutdownhook,顺便学了学Runtime的使用 1. shutdownhook demo示例,证明在程序正常结束的时候会调用,如果kill -9 那肯定就不会调用了 public class ShutdownHookTest { public static

  • java 异常的实例详解

    java 异常的实例详解 1.异常的定义:程序在运行时出现不正常情况. 异常的划分: Error:严重的问题,对于error一般不编写针对性的代码对其进行处理. Exception:非严重的问题,对于exception可以使用针对性的处理方式进行处理. 2.异常的处理:(固定格式) try {需要被检测的代码:} catch(异常类 变量) {处理异常的代码(处理方式):}//这里应当是要有针对性的处理方式 finally {一定会执行的语句:}//通常是关闭资源的代码,因为资源必须得到释放 对

  • Java Process类的详解及实例代码

    Java Process类的详解 前言: 今天用了下Java.lang.Process类,只是初步的学习,并没有深入实践,因为感觉它的用途并不是很大,偶尔才可能用上,如果要经常使用它的人可以自行参考JDk文档. 对Process类的简要说明: Process类是一个抽象类,方法都是抽象的,它封装了一个进程,也就是一个可执行的程序  该类提供进程的输入.执行输出到进程.等待进程的完成和检查进程的退出状态及销毁进程的方法 ProcessBuilder.start()和Runtime.exec方法创建

  • jdk安装、Java环境配置方法详解

    一.简介 jdk是Java语言的软件开发工具包,主要用于移动设备.嵌入式设备上的Java应用程序.jdk是整个Java开发的核心,包含了Java环境,Java工具和Java的基础类库. jre(Java Runtime Environment,Java运行环境),运行Java程序所必须的环境的集合 包含JVM标准实现及Java的核心类库 包含Java虚拟机(jvm) Java核心类库和支持文件 它不包含开发工具(jdk)–编译器.调试器和其他工具. 如果只需要运行Java程序或Applet,下载

  • Mac M1 Java 开发环境配置详解

    JDK 配置 目前 Zulu JDK 支持 M1芯片,下载Zulu JDK 下载后点击安装,在控制台输入java -version ~ % java -version openjdk version "11.0.10" 2021-01-19 LTS OpenJDK Runtime Environment Zulu11.45+27-CA (build 11.0.10+9-LTS) OpenJDK 64-Bit Server VM Zulu11.45+27-CA (build 11.0.1

  • Java System.setProperty()用法详解

    /* * 设置指定键对值的系统属性 * setProperty (String prop, String value); *  * 参数: * prop - 系统属性的名称. * value - 系统属性的值.   *  * 返回: * 系统属性以前的值,如果没有以前的值,则返回 null. *  * 抛出:   * SecurityException - 如果安全管理器存在并且其 checkPermission 方法不允许设置指定属性. * NullPointerException - 如果

  • Java阻塞队列BlockingQueue详解

    目录 队列的类型 数据结构 阻塞队列 BlockingQueue 常见的阻塞队列 BlockingQueue API ArrayBlockingQueue 源码简解 生产者消费者模式 延迟队列 DelayQueue 队列的类型 无限队列(unbounded queue) 无容量限定,只随存储变化 有限队列(bounded queue) 定义了最大容量 向无限队列添加元素的所有操作都将永远不会阻塞(也是线程安全的),因此它可以增长到非常大的容量. 使用无限阻塞队列 BlockingQueue 设计

  • 教你正确的Java扩展方法示例详解

    目录 引言 支持扩展方法的语言 C# Visual Basic Kotlin 主角登场 Lombok @ExtensionMethod Manifold 总结 引言 扩展方法能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型.扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用.对于用 C# 和 Visual Basic 编写的客户端代码,调用扩展方法与调用在类型中实际定义的方法没有明显的差异. 支持扩展方法的语言 其实比较多的编程语言都支持了

  • Java中的静态内部类详解及代码示例

    1. 什么是静态内部类 在Java中有静态代码块.静态变量.静态方法,当然也有静态类,但Java中的静态类只能是Java的内部类,也称为静态嵌套类.静态内部类的定义如下: public class OuterClass { static class StaticInnerClass { ... } } 在介绍静态内部类之前,首先要弄清楚静态内部类与Java其它内部类的区别. 2. 内部类 什么是内部类?将一个类的定义放在另一个类的内部,就是内部类.Java的内部类主要分为成员内部类.局部内部类.

  • Java多线程ForkJoinPool实例详解

    引言 java 7提供了另外一个很有用的线程池框架,Fork/Join框架 理论 Fork/Join框架主要有以下两个类组成. * ForkJoinPool 这个类实现了ExecutorService接口和工作窃取算法(Work-Stealing Algorithm).它管理工作者线程,并提供任务的状态信息,以及任务的执行信息 * ForkJoinTask 这个类是一个将在ForkJoinPool执行的任务的基类. Fork/Join框架提供了在一个任务里执行fork()和join()操作的机制

随机推荐