溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

java如何在運(yùn)行時(shí)獲取環(huán)境信息

發(fā)布時(shí)間:2022-01-14 10:51:34 來(lái)源:億速云 閱讀:372 作者:iii 欄目:大數(shù)據(jù)

本文小編為大家詳細(xì)介紹“java如何在運(yùn)行時(shí)獲取環(huán)境信息”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“java如何在運(yùn)行時(shí)獲取環(huán)境信息”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。

軟件工程師,特別是開(kāi)發(fā)客戶(hù)端產(chǎn)品,App這一類(lèi),都免不了需要判斷當(dāng)前所處環(huán)境。比如客戶(hù)端產(chǎn)品要判斷是Windows/Linux系統(tǒng),x86還是x64等等。 App則需要判斷安卓、iOS的版本,當(dāng)前環(huán)境是否WIFI之類(lèi)的。

對(duì)于 Java 應(yīng)用, 無(wú)論 Web 還是 桌面應(yīng)用,也會(huì)遇到需要判斷當(dāng)前所使用的 JDK 版本,當(dāng)前應(yīng)用對(duì)應(yīng)的操作系統(tǒng)等等。

比如我們?cè)趲啄昵白鰬?yīng)用服務(wù)器集群管理與監(jiān)控時(shí),需要判斷應(yīng)用服務(wù)器所屬物理機(jī)器的CPU以及內(nèi)存的使用率、對(duì)于服務(wù)器實(shí)例進(jìn)行操作,對(duì)于不同的JVM 實(shí)現(xiàn),采用不同的attach機(jī)制等等。當(dāng)時(shí)是使用 Sigar 進(jìn)行這些硬件信息的獲取。

由于提供的是All in One 的版本,所以需要判斷操作系統(tǒng)類(lèi)型,來(lái)判斷加載 Sigar 的Windows支持 dll 文件還是Linux 支持 so 文件。

當(dāng)然獲取操作系統(tǒng)類(lèi)型、版本都較容易,直接通過(guò)System 的getProperty再加上對(duì)應(yīng)的名稱(chēng)就能拿到,比如「os.name」,「os.arch」等。對(duì)于 JVM 的廠商,則可以通過(guò)「java.vm.vendor」來(lái)得到,完整的可以通過(guò)System.getProperties全部拿到。

如果習(xí)慣使用JMX 讀取Platform 的 MBean,也可以通過(guò) JMX來(lái)獲取,便捷操作類(lèi)似這樣:

OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
System.out.println(os.getName());

本質(zhì)上也都是一樣的。

那除了這種方式,還有哪些方式可以獲取到呢?一般開(kāi)源軟件又是怎么做的呢?

我們來(lái)看 Tomcat 內(nèi)部怎么實(shí)現(xiàn)的。

我們發(fā)現(xiàn), Tomcat 內(nèi)部,對(duì)于通過(guò) System 的 properties獲取到的,基本都是用來(lái)打印 Log 和輸出使用,對(duì)于應(yīng)用內(nèi)的控制,基本沒(méi)看到使用。

java如何在運(yùn)行時(shí)獲取環(huán)境信息

那 Tomcat在判斷版本時(shí),是怎么做的呢?為什么不直接用這個(gè)呢?

首先看怎么做的。

前面的文章提到過(guò), Tomcat 對(duì)于內(nèi)存泄漏做了一些努力,比如先Hold 一塊內(nèi)存這種(Tomcat與內(nèi)存泄露處理),也比如防止內(nèi)存泄漏的PreventionListener,會(huì)先將可能共用的 class加載到Common classLoader里(Tomcat類(lèi)加載器以及應(yīng)用間class隔離與共享,類(lèi)加載器與類(lèi)沖突)。

那這里加載到 Common classLoader這些常用 class時(shí),就需要判斷當(dāng)前是Java 哪個(gè)版本,因?yàn)橛行?class 是某些版之后才出現(xiàn)的。

具體實(shí)現(xiàn)是這個(gè)樣子:

// Trigger a call to sun.awt.AppContext.getAppContext(). This
// will pin the system class loader in memory but that shouldn't
// be an issue.
if (appContextProtection && !JreCompat.isJre8Available()) {
   ImageIO.getCacheDirectory();
}

// Trigger the creation of the AWT (AWT-Windows, AWT-XAWT,
// etc.) thread
if (awtThreadProtection && !JreCompat.isJre9Available()) {
   java.awt.Toolkit.getDefaultToolkit();
}

什么時(shí)候 Available了?

static {
   // This is Tomcat 8 with a minimum Java version of Java 7. The latest
   // Java version the optional features require is Java 9.
   // Look for the highest supported JVM first
   if (Jre9Compat.isSupported()) {
       instance = new Jre9Compat();
       jre9Available = true;
       jre8Available = true;
   }
   else if (Jre8Compat.isSupported()) {
       instance = new Jre8Compat();
       jre9Available = false;
       jre8Available = true;
   } else {
       instance = new JreCompat();
       jre9Available = false;
       jre8Available = false;
   }
}

具體是不是支持是直接通過(guò)加載特定版JDK 對(duì)應(yīng)的 class 來(lái)判斷

static {
   Method m1 = null;
   try {
       // The class is Java6+...
       Class<?> c1 = Class.forName("javax.net.ssl.SSLParameters");
       // ...but this method is Java8+
       m1 = c1.getMethod("setUseCipherSuitesOrder", boolean.class);
   } catch (SecurityException e) {
       // Should never happen
   } catch (NoSuchMethodException e) {
       // Expected on Java < 8
   } catch (ClassNotFoundException e) {
       // Should never happen
   }
   setUseCipherSuitesOrderMethod = m1;
}

通過(guò)這種加載 class 的方式,和 我們前面通過(guò) System.property獲取,有啥區(qū)別呢?

要知道, System 的 Property 是個(gè)系統(tǒng)屬性,是可配置的,也就是說(shuō),誰(shuí)都可以進(jìn)行setProperty的操作。如果不巧被別人改了,那你的程序可能就會(huì)出現(xiàn)不符合你預(yù)期的行為。

而加載類(lèi)的形式,并不受其他人的影響。是最真實(shí)的一線聲音。

這樣的判斷不方式,不僅 Tomcat 自己,其他框架也有在用。我們來(lái)看 Spring Boot。

Boot 執(zhí)行的時(shí)候,有時(shí)候會(huì)判斷當(dāng)前應(yīng)用是否需要支持 Web, 類(lèi)似于是否加載了 Spring MVC 這種。

private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",

    "org.springframework.web.context.ConfigurableWebApplicationContext" };

    

     private boolean deduceWebEnvironment() {

     for (String className : WEB_ENVIRONMENT_CLASSES) {

     if (!ClassUtils.isPresent(className, null)) {

     return false;

     }

     }

     return true;

     }

然后在啟動(dòng)時(shí)候,會(huì)調(diào)用deduceWebEnvironment 方法,從而決定一些執(zhí)行的邏輯。

還有其他方式么? 如何不想自己手工處理,可以使用一些工具類(lèi),比如 Apache 的 commons-lang, 提供了一個(gè) SystemUtils 可以直接。例如判斷操作系統(tǒng)和 Java 版本

if (SystemUtils.IS_JAVA_1_7) {
   System.out.println("Hello 1.7");
}

工具類(lèi)是怎么做的呢?

public static final String JAVA_VERSION = getSystemProperty("java.version");
 
private static String getJavaVersionTrimmed() {
   if(JAVA_VERSION != null) {
       for(int i = 0; i < JAVA_VERSION.length(); ++i) {
           char ch = JAVA_VERSION.charAt(i);
           if(ch >= 48 && ch <= 57) {
               return JAVA_VERSION.substring(i);
           }
       }
   }

   return null;
}

說(shuō)到底,也還是System.getProperty.

所以,在檢測(cè)環(huán)境的時(shí)候,我們可以通過(guò)System.getProperty,也可以通過(guò) Tomcat 和 Spring 這種加載 class 的方式?;蛘吒纱嘀苯佑霉ぞ哳?lèi)。 你還用過(guò)啥辦法呢?

讀到這里,這篇“java如何在運(yùn)行時(shí)獲取環(huán)境信息”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過(guò)才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI