Java|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 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 bytesfor (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; FileInputStreamf0 = 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还是很方便的,用来做停止任务的后续处理。
【Java|Java Runtime的使用详解】以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
推荐阅读
- MyBatis|MyBatis 接收数据库中没有的字段的解决
- 配合Swagger使用绝佳的两款直观易用JSON可视化工具
- Java用邻接矩阵存储图的示例代码
- Java|Java easyExcel的复杂表头多级表头导入
- Java用邻接表存储图的示例代码
- 自带IDEA插件的阿里开源诊断神器Arthas线上项目BUG调试
- J2EE|学生管理系统的增删改查
- 焦点|扛住了史上最严重制裁,俄罗斯经济为何比预想的能打?
- 软件测试|软件测试开发基础|测开中的几个工具开发实战
- java|使用堆内内存HeapByteBuffer的注意事项