詳解Springboot工程中如何快速判斷web應(yīng)用服務(wù)器類型
在 Spring Boot 工程中快速判斷 Web 應(yīng)用服務(wù)器類型,可以從運行時環(huán)境、Spring Boot 特有 API、底層類加載器、HTTP 響應(yīng)和外部命令等多個層面入手。下面是幾種常見方法的速覽表:
| 方法 | 原理簡述 | 代碼復(fù)雜度 | 通用性 | 推薦度 |
|---|---|---|---|---|
| 注入 ServletContext | 直接調(diào)用 getServerInfo() 獲取服務(wù)器信息 | ★☆☆☆☆ | 極高 (適用于所有 Servlet 容器) | ????? |
| 檢查特定類是否存在 | 通過 Class.forName() 加載特定服務(wù)器的關(guān)鍵類 | ★★☆☆☆ | 高 | ???? |
| 利用 Spring Boot 條件注解 | 使用 @ConditionalOnClass 注解聲明 Bean | ★★☆☆☆ | 一般 (適用于 Spring 環(huán)境) | ??? |
| 監(jiān)聽容器初始化事件 | 在應(yīng)用啟動時監(jiān)聽 ServletWebServerInitializedEvent 事件 | ★★☆☆☆ | 一般 (適用于 Spring Boot) | ??? |
| 查看啟動日志 | 直接觀察應(yīng)用啟動時的控制臺日志輸出 | ☆☆☆☆☆ | 極高 | ????? |
| 使用 Actuator 端點 | 訪問 /actuator/env 端點查看服務(wù)器相關(guān)配置 | ★★☆☆☆ | 一般 | ??? |
| 檢查特定系統(tǒng)屬性或 JMX | 讀取 java.vm.vendor 或查詢 JMX MBean | ★★★☆☆ | 中 | ?? |
| 通過外部命令或端口號推斷 | 使用 netstat 或 ps 命令在操作系統(tǒng)層面查詢 | ★★★☆☆ | 低 (僅限手動排查) | ? |
方法一:通過 ServletContext 獲取服務(wù)器信息(推薦)
這是最直接、最可靠的方式。你可以在任何 Spring Bean 中注入 ServletContext 對象,并調(diào)用 getServerInfo() 方法。該方法會返回一個字符串,其中包含了當(dāng)前正在運行的 Servlet 容器的名稱和版本信息。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.ServletContext;
@Service
public class ServerInfoService {
@Autowired
private ServletContext servletContext;
public void printServerInfo() {
String serverInfo = servletContext.getServerInfo();
System.out.println("服務(wù)器信息: " + serverInfo);
// 對于 Tomcat,輸出可能是 "Apache Tomcat/9.0.83"
// 對于 Jetty,輸出可能是 "Jetty/9.4.53.v20231009"
// 對于 Undertow,輸出可能是 "Undertow - 2.2.24.Final"
}
}根據(jù) getServerInfo() 返回的內(nèi)容進行判斷時,注意對版本號部分進行清理,避免因版本差異導(dǎo)致匹配失敗。
方法二:檢查特定類的存在性
通過 Class.forName() 方法檢測特定服務(wù)器的關(guān)鍵類是否存在于當(dāng)前應(yīng)用的 Classpath 中,從而判斷其類型。
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class ServerDetector {
public enum ServerType {
TOMCAT, JETTY, UNDERTOW, JBOSS, WEBLOGIC, WEBSPHERE, UNKNOWN
}
private static ServerType detectedServer;
@PostConstruct
public void detect() {
detectedServer = determineServerType();
System.out.println("檢測到服務(wù)器類型: " + detectedServer);
}
public static ServerType determineServerType() {
if (isClassPresent("org.apache.catalina.startup.Tomcat")) return ServerType.TOMCAT;
if (isClassPresent("org.eclipse.jetty.server.Server")) return ServerType.JETTY;
if (isClassPresent("io.undertow.Undertow")) return ServerType.UNDERTOW;
if (isClassPresent("org.jboss.Main")) return ServerType.JBOSS;
if (isClassPresent("weblogic.Server")) return ServerType.WEBLOGIC;
if (isClassPresent("com.ibm.websphere.product.VersionInfo")) return ServerType.WEBSPHERE;
return ServerType.UNKNOWN;
}
private static boolean isClassPresent(String className) {
try {
Class.forName(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}方法三:利用 Spring Boot 的條件注解
這種方式適合用于控制某些特定服務(wù)器下 Bean 的加載,是一種聲明式的判斷方法。
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ServerSpecificConfig {
@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public String tomcatOnlyBean() {
return "僅當(dāng)應(yīng)用運行在 Tomcat 服務(wù)器上時,此 Bean 才會被創(chuàng)建";
}
}這個例子也可以作為快速判斷的依據(jù),當(dāng)你看到 tomcatOnlyBean 在應(yīng)用上下文中被創(chuàng)建,就可以認為當(dāng)前運行的是 Tomcat 容器。
方法四:監(jiān)聽容器初始化事件
通過實現(xiàn) ApplicationListener<ServletWebServerInitializedEvent> 接口,可以在 Servlet 容器完成初始化后獲取 WebServer 實例,從而獲取服務(wù)器的具體實現(xiàn)類,反推出其類型。
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class WebServerListener implements ApplicationListener<WebServerInitializedEvent> {
@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
// 獲取 WebServer 實例,其實現(xiàn)類通常是 TomcatWebServer、JettyWebServer、UndertowWebServer 等
Class<?> webServerClass = event.getWebServer().getClass();
System.out.println("WebServer 實現(xiàn)類: " + webServerClass.getName());
// 可根據(jù)實現(xiàn)類名判斷服務(wù)器類型
if (webServerClass.getName().contains("Tomcat")) {
System.out.println("當(dāng)前運行在 Tomcat 服務(wù)器上");
}
}
}補充說明
通用性與準確性:ServletContext.getServerInfo() 是標準 Java Servlet 規(guī)范的一部分,在所有支持 Servlet 規(guī)范的容器中均可使用,且直接提供官方定義的服務(wù)器名稱,是最可靠的方法。
為什么可能有“多種判斷”:在某些特殊場景下(例如需要與不支持 Servlet API 的老舊代碼集成),可能需要采用其他方式。另外,getServerInfo() 返回的字符串版本號格式因服務(wù)器而異,有時需要自行解析。
方法選擇建議:對絕大多數(shù) Spring Boot 應(yīng)用,最推薦 ServletContext.getServerInfo()。若無法獲取 ServletContext,可使用“檢查類是否存在”的方法作為替代。若要根據(jù)服務(wù)器類型選擇性加載 Bean,應(yīng)優(yōu)先使用 Spring 的條件注解。
方法補充
該代碼片段通過檢查Spring應(yīng)用上下文中的Bean定義來判斷當(dāng)前使用的是Tomcat還是Jetty容器。使用@PostConstruct注解在初始化時執(zhí)行檢測邏輯,通過掃描Bean名稱是否包含EmbeddedTomcat或EmbeddedJetty來設(shè)置相應(yīng)的布爾標志,并輸出日志記錄檢測結(jié)果。這種動態(tài)識別方式適用于需要針對不同嵌入式容器做差異化處理的場景。
核心源碼
boolean isTomcat;
boolean isJetty;
@Autowired
ApplicationContext applicationContext;
@PostConstruct
private void init()
{
isTomcat = Stream.of(applicationContext.getBeanDefinitionNames()).anyMatch(name -> StringUtils.containsIgnoreCase(name, "EmbeddedTomcat"));
isJetty = Stream.of(applicationContext.getBeanDefinitionNames()).anyMatch(name -> StringUtils.containsIgnoreCase(name, "EmbeddedJetty"));
log.info("#### isTomcat: {}", isTomcat);
log.info("#### isJetty: {}", isJetty);
}
典型應(yīng)用
import java.io.File;
import java.io.IOException;
import java.util.stream.Stream;
import javax.annotation.PostConstruct;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.fly.demo.common.JsonResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Api(tags = "文件上傳(simple)")
@RestController
@RequestMapping("/simple/file")
public class SimpleFileController
{
boolean isTomcat;
boolean isJetty;
@Autowired
ApplicationContext applicationContext;
@PostConstruct
private void init()
{
isTomcat = Stream.of(applicationContext.getBeanDefinitionNames()).anyMatch(name -> StringUtils.containsIgnoreCase(name, "EmbeddedTomcat"));
isJetty = Stream.of(applicationContext.getBeanDefinitionNames()).anyMatch(name -> StringUtils.containsIgnoreCase(name, "EmbeddedJetty"));
log.info("#### isTomcat: {}", isTomcat);
log.info("#### isJetty: {}", isJetty);
}
@ApiOperation("文件上傳")
@PostMapping("/upload")
public JsonResult<?> upload(@RequestParam MultipartFile file)
throws IOException
{
File rootDir = new File("upload");
File dest;
if (isTomcat)
{
if (RandomUtils.nextBoolean())
{
log.info("### transferTo");
dest = new File(rootDir.getCanonicalPath() + File.separator + file.getOriginalFilename());
file.transferTo(dest);
}
else
{
log.info("### copyInputStreamToFile");
dest = new File(rootDir, file.getOriginalFilename());
FileUtils.copyInputStreamToFile(file.getInputStream(), dest);
}
}
else
{
log.info("### copyInputStreamToFile");
dest = new File(rootDir, file.getOriginalFilename());
FileUtils.copyInputStreamToFile(file.getInputStream(), dest);
}
return JsonResult.success(dest.getName());
}
}
到此這篇關(guān)于詳解Springboot工程中如何快速判斷web應(yīng)用服務(wù)器類型的文章就介紹到這了,更多相關(guān)Springboot判斷web應(yīng)用服務(wù)器類型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java圖形界面之JFrame,JLabel,JButton詳解
這篇文章主要介紹了Java圖形界面之JFrame、JLabel、JButton詳解,文中有非常詳細的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04
SpringBoot整合screw實現(xiàn)自動生成數(shù)據(jù)庫設(shè)計文檔
使用navicat工作的話,導(dǎo)出的格式是excel不符合格式,還得自己整理。所以本文將用screw工具包,整合到springboot的項目中便可以自動生成數(shù)據(jù)庫設(shè)計文檔,非常方便,下面就分享一下教程2022-11-11
idea maven編譯報錯Java heap space的解決方法
這篇文章主要為大家詳細介紹了idea maven編譯報錯Java heap space的相關(guān)解決方法,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-04-04

