Java Runtime的使用详解

作者:fenglllle 时间:2021-10-23 06:46:39 

前言

最近做项目框架,需要在框架结束的时候,关闭服务器连接,清除部分框架运行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

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

Java Runtime的使用详解

结果如下,shutdownhook已执行。

Java Runtime的使用详解

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);
           }
       }
   }
}

结果如下

Java Runtime的使用详解

而正常执行结果

Java Runtime的使用详解

但是这个方法有远程执行风险,即在浏览器端通过这个方法执行特定指令,比如执行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);
           }
       }
   }

结果😓

Java Runtime的使用详解

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

Java 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调用

Java Runtime的使用详解

加载jar文件

Java Runtime的使用详解

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

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

来源:https://blog.csdn.net/fenglllle/article/details/89525533

标签:Java,Runtime
0
投稿

猜你喜欢

  • springboot2.x 接入阿里云市场短信发送的实现

    2023-09-20 23:03:57
  • Spring5中的WebClient使用方法详解

    2023-08-05 14:50:24
  • 分享java中设置代理的两种方式

    2023-10-28 10:48:52
  • Spring不能注入Static变量的原因及Spring注入静态变量

    2023-11-24 04:16:36
  • Java实战之在线租房系统的实现

    2022-09-29 04:44:18
  • 使用Postman传递arraylist数据给springboot方式

    2022-08-27 01:13:01
  • java并发高的情况下用ThreadLocalRandom来生成随机数

    2022-10-30 12:42:03
  • c#使用process.start启动程序报错解决方法

    2021-07-28 01:20:20
  • springBoot解决static和@Component遇到的bug

    2022-12-31 01:23:27
  • Java使用Hutool实现AES、DES加密解密的方法

    2021-06-03 16:49:57
  • java实现zip,gzip,7z,zlib格式的压缩打包

    2023-08-13 08:56:59
  • 浅谈Java编程之if-else的优化技巧总结

    2023-06-02 23:28:12
  • JAVA使用POI(XSSFWORKBOOK)读取EXCEL文件过程解析

    2023-03-01 16:36:39
  • springboot相关面试题汇总详解

    2023-10-06 17:16:11
  • C#词法分析器之正则表达式的使用

    2023-06-21 13:10:58
  • Java核心编程之文件随机读写类RandomAccessFile详解

    2023-11-28 17:40:05
  • JAVA面试题之Forward与Redirect的区别详解

    2023-11-25 02:27:15
  • SpringCloud Edgware.SR3版本中Ribbon的timeout设置方法

    2023-03-07 10:45:46
  • Java中高效判断数组中是否包含某个元素的几种方法

    2022-02-21 05:46:39
  • 浅谈Java序列化和hessian序列化的差异

    2022-11-17 07:46:13
  • asp之家 软件编程 m.aspxhome.com