《Java 配 Shell 等於美酒加咖啡》
化學中我們得知「氫氣加氧氣在點燃的情況下會生成水」。
生活中我們得知「良辰加美景的情況下會得到千金春宵一刻」。
技術上又何嘗不是如此呢?先假設一個場景:BOSS 讓你實現一個服務監控的指揮室,能看到每個伺服器的磁碟剩餘空間,能看到。。。能看到。。。
其實講真,實現思路有很多,但是不管黑貓白貓能抓住老鼠都是好貓,今天我們嘗試用 Java 與 Shell 搭配一下,看看是否會產生驚奇的反應。
1. 首先透過 JDK 原始碼,品一品 Runtime 這杯美酒。
上圖是摘取 JDK 中 Runtime 的部分原始碼,主要分成 4 大程式碼段來粗略認識她。
第一塊程式碼段,可以看出 Runtime 構造私有化,提供了靜態屬性,並提前建立物件例項,並提供獲取例項的靜態方法,這不就是單例設計模式的使用麼,當有面試官再問設計模式,拿去狂噴。
第二塊程式碼段,主要是 addShutdownHook() 方法,新增關閉的鉤子,說的直白點,其實允許研發人員插入一段在 JVM 關閉時執行的程式碼。例如在搭建服務框架時,面對需要完成優雅停服,打掃戰場,釋放資源等等,諸如此類的場景下都很有用。其中在 Tomcat、Jetty 等容器中都可以看到 shutdownHook 的身影。
Runtime runtime = Runtime.getRuntime();
runtime.addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("打掃戰場,釋放資源,完成優雅停服");
}
});
System.out.println("服務啟動完成");
程式碼執行效果如下。
服務啟動完成
打掃戰場,釋放資源,完成優雅停服
第三塊程式碼段,主要展現 JDK 針對 Runtime 提供的系列 exec 過載方法,這個是本次分享的重點,重頭戲最後再說。
第四塊程式碼段,主要是 Runtime 提供的一些獲取系統資訊的 API,直接拋程式碼,拿去用就行了。
System.out.println(String.format("JVM可用本機CPU核心數 %d", runtime.availableProcessors()));
//預設為系統的1/4
System.out.println(String.format("最大可用記憶體空間 %d M", runtime.maxMemory() / 1024 / 1024));
//預設為系統的1/64
System.out.println(String.format("可用記憶體空間 %d M", runtime.totalMemory() / 1024 / 1024));
System.out.println(String.format("空閒記憶體空間 %d M", runtime.freeMemory() / 1024 / 1024));
程式碼執行輸出如下,其實真實環境中不妨用模板引擎 FreeMarker 渲染,然後透過郵件告警,實現的逼格高一些。
2. 在詳細說 Runtime.exec() 這個重頭戲之前,再品一品 df 這款咖啡。
Linux df 命令,用於顯示目前在系統上的磁碟使用情況統計,主要用於檢視磁碟的分割槽,磁碟已使用的空間,剩餘的空間。
命令如下:
df [選項]... [FILE]...
常用選項如下:
3. Runtime 美酒加 Shell 咖啡會發生什麼呢?
重頭戲開始,回到 Runtime 的原始碼,我們看到 exec() 系列方法會幫我們啟動一個 Process 程序,那不妨把 df -h 命令傳入進去一探究竟。
public class Foo {
public static void main(String[] args) throws Exception {
//df命令用於檢視磁碟的分割槽,磁碟已使用的空間,剩餘的空間
//df -h以合適的單位來顯示資訊
System.out.println(exec("df -h"));
private static String exec(String command) throws Exception {
String[] cmd = {"/bin/sh", "-c", command};
StringBuilder out = new StringBuilder();
BufferedReader reader = null;
InputStream in = null;
try {
Process process = Runtime.getRuntime().exec(cmd);
in = process.getInputStream();
reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
out.append(line + "\n");
process.waitFor();
} finally {
if (reader != null) {
reader.close();
return out.toString();
程式碼中會發現呼叫了 process 的 waitFor() 方法,此方法作用會導致當前執行緒等待,一直要等到由該 Process 物件表示的程序終止,其實也就是等待把 exec 裡面啟動的 Process 中的所有事都幹完(生產上出問題的大多出在這兒),程式碼執行效果如下。
效果確實可以,那麼這麼一來,想監控統計什麼功能,不妨直接把命令交給 Java 程式去執行即可。
4.
其實 Runtime.exec() 方法設計,可接受一個單獨的字串,這個字串是透過空格來分隔可執行命令程式和引數的;當然也可以接受字串陣列引數。
如上圖所示,ProcessBuilder 的方法入參是一個List<String>或者多個字串。
相同點是 ProcessBuilder.start() 和 Runtime.exec() 方法都被用來建立一個作業系統程序(執行命令列操作)。
最後依然用阿里新六脈神劍中的三脈送給大家:今天最好的表現是明天最低的要求;此時此刻非我莫屬;認真生活快樂工作!
《Java 配 Shell 等於美酒加咖啡》
化學中我們得知「氫氣加氧氣在點燃的情況下會生成水」。
生活中我們得知「良辰加美景的情況下會得到千金春宵一刻」。
技術上又何嘗不是如此呢?先假設一個場景:BOSS 讓你實現一個服務監控的指揮室,能看到每個伺服器的磁碟剩餘空間,能看到。。。能看到。。。
其實講真,實現思路有很多,但是不管黑貓白貓能抓住老鼠都是好貓,今天我們嘗試用 Java 與 Shell 搭配一下,看看是否會產生驚奇的反應。
1. 首先透過 JDK 原始碼,品一品 Runtime 這杯美酒。
上圖是摘取 JDK 中 Runtime 的部分原始碼,主要分成 4 大程式碼段來粗略認識她。
第一塊程式碼段,可以看出 Runtime 構造私有化,提供了靜態屬性,並提前建立物件例項,並提供獲取例項的靜態方法,這不就是單例設計模式的使用麼,當有面試官再問設計模式,拿去狂噴。
第二塊程式碼段,主要是 addShutdownHook() 方法,新增關閉的鉤子,說的直白點,其實允許研發人員插入一段在 JVM 關閉時執行的程式碼。例如在搭建服務框架時,面對需要完成優雅停服,打掃戰場,釋放資源等等,諸如此類的場景下都很有用。其中在 Tomcat、Jetty 等容器中都可以看到 shutdownHook 的身影。
Runtime runtime = Runtime.getRuntime();
runtime.addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("打掃戰場,釋放資源,完成優雅停服");
}
});
System.out.println("服務啟動完成");
程式碼執行效果如下。
服務啟動完成
打掃戰場,釋放資源,完成優雅停服
第三塊程式碼段,主要展現 JDK 針對 Runtime 提供的系列 exec 過載方法,這個是本次分享的重點,重頭戲最後再說。
第四塊程式碼段,主要是 Runtime 提供的一些獲取系統資訊的 API,直接拋程式碼,拿去用就行了。
Runtime runtime = Runtime.getRuntime();
System.out.println(String.format("JVM可用本機CPU核心數 %d", runtime.availableProcessors()));
//預設為系統的1/4
System.out.println(String.format("最大可用記憶體空間 %d M", runtime.maxMemory() / 1024 / 1024));
//預設為系統的1/64
System.out.println(String.format("可用記憶體空間 %d M", runtime.totalMemory() / 1024 / 1024));
System.out.println(String.format("空閒記憶體空間 %d M", runtime.freeMemory() / 1024 / 1024));
程式碼執行輸出如下,其實真實環境中不妨用模板引擎 FreeMarker 渲染,然後透過郵件告警,實現的逼格高一些。
2. 在詳細說 Runtime.exec() 這個重頭戲之前,再品一品 df 這款咖啡。
Linux df 命令,用於顯示目前在系統上的磁碟使用情況統計,主要用於檢視磁碟的分割槽,磁碟已使用的空間,剩餘的空間。
命令如下:
df [選項]... [FILE]...
常用選項如下:
3. Runtime 美酒加 Shell 咖啡會發生什麼呢?
重頭戲開始,回到 Runtime 的原始碼,我們看到 exec() 系列方法會幫我們啟動一個 Process 程序,那不妨把 df -h 命令傳入進去一探究竟。
public class Foo {
public static void main(String[] args) throws Exception {
//df命令用於檢視磁碟的分割槽,磁碟已使用的空間,剩餘的空間
//df -h以合適的單位來顯示資訊
System.out.println(exec("df -h"));
}
private static String exec(String command) throws Exception {
String[] cmd = {"/bin/sh", "-c", command};
StringBuilder out = new StringBuilder();
BufferedReader reader = null;
InputStream in = null;
try {
Process process = Runtime.getRuntime().exec(cmd);
in = process.getInputStream();
reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
out.append(line + "\n");
}
process.waitFor();
} finally {
if (reader != null) {
reader.close();
}
}
return out.toString();
}
}
程式碼中會發現呼叫了 process 的 waitFor() 方法,此方法作用會導致當前執行緒等待,一直要等到由該 Process 物件表示的程序終止,其實也就是等待把 exec 裡面啟動的 Process 中的所有事都幹完(生產上出問題的大多出在這兒),程式碼執行效果如下。
效果確實可以,那麼這麼一來,想監控統計什麼功能,不妨直接把命令交給 Java 程式去執行即可。
4.
其實 Runtime.exec() 方法設計,可接受一個單獨的字串,這個字串是透過空格來分隔可執行命令程式和引數的;當然也可以接受字串陣列引數。
如上圖所示,ProcessBuilder 的方法入參是一個List<String>或者多個字串。
相同點是 ProcessBuilder.start() 和 Runtime.exec() 方法都被用來建立一個作業系統程序(執行命令列操作)。
最後依然用阿里新六脈神劍中的三脈送給大家:今天最好的表現是明天最低的要求;此時此刻非我莫屬;認真生活快樂工作!