Java?Runtime的使用詳解
前言
最近做項目框架,需要在框架結(jié)束的時候,關(guān)閉服務(wù)器連接,清除部分框架運行l(wèi)ock文件,這里就想到了shutdownhook,順便學(xué)了學(xué)Runtime的使用
1. shutdownhook
demo示例,證明在程序正常結(jié)束的時候會調(diào)用,如果kill -9 那肯定就不會調(diào)用了
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================"); } }
正常運行結(jié)束,結(jié)果如下
==============application start================
==============application end================
--------------hook 1----------------
--------------hook 2----------------
Process finished with exit code 0
如果暫停,點擊下圖左下角的正方形紅圖標(biāo),停止正在運行的應(yīng)用
結(jié)果如下,shutdownhook已執(zhí)行。
shutdownhook可以處理程序正常結(jié)束的時候,刪除文件,關(guān)閉連接等
2. exec執(zhí)行
2.1 常規(guī)命令執(zhí)行
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); } } } }
結(jié)果如下
而正常執(zhí)行結(jié)果
但是這個方法有遠(yuǎn)程執(zhí)行風(fēng)險,即在瀏覽器端通過這個方法執(zhí)行特定指令,比如執(zhí)行rm -rf *,結(jié)果就很……
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); } } }
結(jié)果??
sh -c的參數(shù)要分離,不然runtime會認(rèn)為是一個參數(shù)
2.3源碼分析
跟蹤代碼,使用ProcessImpl來執(zhí)行指令
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 環(huán)境
/** * 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. 總結(jié)
Runtime用處非常多,偏底層
比如gc調(diào)用
加載jar文件
Runtime功能強大,但需要合理利用,很多攻擊是通過Runtime執(zhí)行的漏洞
但是使用shutdownhook還是很方便的,用來做停止任務(wù)的后續(xù)處理。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
通過java備份恢復(fù)mysql數(shù)據(jù)庫的實現(xiàn)代碼
這篇文章主要介紹了如何通過java備份恢復(fù)mysql數(shù)據(jù)庫,其實一般情況下通過bat或sh就可以,這里主要是介紹了java的實現(xiàn)思路,喜歡的朋友可以參考下2013-09-09Javaweb 鼠標(biāo)移入移出表格顏色變化的實現(xiàn)
這篇文章主要介紹了Javaweb 鼠標(biāo)移入移出表格顏色變化的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09springmvc+spring+mybatis實現(xiàn)用戶登錄功能(上)
這篇文章主要為大家詳細(xì)介紹了springmvc+spring+mybatis實現(xiàn)用戶登錄功能,比較基礎(chǔ)的學(xué)習(xí)教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07