在Java中能執行命令的類其實並很少,不像php那樣各類的命令執行函數。在Java中目前所知的能執行命令的類也就兩種,分別是Runtime和 ProcessBuilder類。php
關於Runtime具體的使用能夠看這篇文章,反射去調用Runtime。html
Java學習之反射篇java
@WebServlet("/execServlet") public class execServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String exec = request.getParameter("exec"); Process res = Runtime.getRuntime().exec(exec); InputStream inputStream = res.getInputStream(); ServletOutputStream outputStream = response.getOutputStream(); int len; byte[] bytes = new byte[1024]; while ((len = inputStream.read(bytes))!=-1){ outputStream.write(bytes,0,len); }
這裏來運行一下,傳入一個命令看看能不能正常運行。數組
http://localhost:8080/untitled9_war_exploded/execServlet?exec=ipconfig
咱們來看看他具體的實現,首先跟蹤一下getRuntime()方法。函數
看到調用方法就不作任何的處理就直接返回了currentRuntime對象,上面能夠看到currentRuntime是Runtime的實例對象。也就是說每次調用getRuntime()方法都會new一個Runtime的對象。學習
官方文檔說明:ui
每一個Java應用程序都有一個Runtime類的Runtime ,容許應用程序與運行應用程序的環境進行接口。 當前運行時能夠從getRuntime方法得到。 應用程序沒法建立本身的此類的實例。
再來跟蹤一下exec方法,看看exec方法的具體實現this
exec中有多個重載方法,在跟蹤返回值的exec操作系統
仍是他的重載方法,再跟蹤命令行
這裏會發現不同了,返回了
return new ProcessBuilder(cmdarray) .environment(envp) .directory(dir) .start();
在跟蹤的時候會發現,咱們傳入的ipconfig會在cmdarray變量裏面進行傳入,其餘值都是null。也就是說該類的底層其實仍是ProcessBuilder這個類來進行實現的。
前面的Process res = Runtime.getRuntime().exec(exec);
返回類型爲 Process,是經過new ProcessBuilder並傳入命令,再去調用start方法返回得來的。
但咱們後面的res.getInputStream();
,getInputStream();是怎麼來的呢?Process 是一個抽象類,包含了6個抽象方法。
abstract public OutputStream getOutputStream(); abstract public InputStream getInputStream(); abstract public InputStream getErrorStream(); abstract public int waitFor() throws InterruptedException; abstract public int exitValue(); abstract public void destroy();
跟蹤一下,這幾個方法,調用的方法,除了start方法外,其餘的幾個方法都是進行設置值。這裏就不一一演示了。
return new ProcessBuilder(cmdarray) .environment(envp) .directory(dir) .start();
跟蹤start方法
能夠看到start方法裏面,調用了process的實現類。
package com.test; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; @WebServlet("/exec2Servlet") public class exec2Servlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String exec = request.getParameter("exec"); ServletOutputStream outputStream = response.getOutputStream(); ProcessBuilder processBuilder = new ProcessBuilder(exec); Process res = processBuilder.start(); InputStream inputStream = res.getInputStream(); int len ; byte[] bytes =new byte[1024]; while ((len = inputStream.read(bytes))!=-1){ outputStream.write(bytes,0,len); } } }
使用ProcessBuilder的方式也是能夠執行命令的。
後面專門開一個標題,作一個前面知識的補充。
destroy() 殺掉子進程。 exitValue() 返回子進程的出口值。 InputStream getErrorStream() 得到子進程的錯誤流。 InputStream getInputStream() 得到子進程的輸入流。 OutputStream getOutputStream() 得到子進程的輸出流。 waitFor() 致使當前線程等待,若是必要,一直要等到由該 Process 對象表示的進程已經終止。
前面會發現的一個問題在這裏作一個解疑,process既然是抽象類,不能new對象,獲取到他的實例類的呢?
前面咱們調試代碼的時候,發現了可使用ProcessBuilder的Start方法進行返回,第二種方法就是Runtime的exec方法,但Runtime的exec方法底層依然是ProcessBuilder的Start方法進行實現的。
這裏還有必要說的一個問題,ProcessBuilder與Runtime.exec()的區別是什麼?
在網上查閱了一些思路得出瞭如下的結論。
ProcessBuilder.start() 和 Runtime.exec() 方法都被用來建立一個操做系統進程(執行命令行操做),並返回 Process 子類的一個實例,該實例可用來控制進程狀態並得到相關信息。 ProcessBuilder.start() 和 Runtime.exec()傳遞的參數有所不一樣,Runtime.exec()可接受一個單獨的字符串,這個字符串是經過空格來分隔可執行命令程序和參數的;也能夠接受字符串數組參數。而ProcessBuilder的構造函數是一個字符串列表或者數組。列表中第一個參數是可執行命令程序,其餘的是命令行執行是須要的參數。
https://honeypps.com/java/process-builder-quick-start/
在遇到一些問題的時候,多打debug也是個不錯的選擇,多打debug能比較清晰的分析到問題所在。例如調試代碼的時候,能夠打個debug一層層去分析也會發現一些有意思的東西。