Java Runtime的使用详解

前言

最近做项目框架,需要在框架结束的时候,关闭服务器连接,清除部分框架运行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还是很方便的,用来做停止任务的后续处理。

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

以上是 Java Runtime的使用详解 的全部内容, 来源链接: utcz.com/p/251539.html

回到顶部