SpringBoot(六)之內嵌容器
文章目錄
- SpringBoot(六)之內嵌容器
- 內嵌容器的特點
- 如何替換默認容器
- 1.pom形式
- 2.主動配置
- 如何通過配置切換serlvet容器
Spring Boot 提供了一種便捷的方式來創建獨立運行的 Spring 應用程序,內嵌容器(如 Tomcat、Jetty 或 Undertow)是其核心特性之一。這使得開發者不需要將應用程序部署到外部的應用服務器上,而是通過內嵌容器直接運行應用。這種方式簡化了部署流程,并且提高了開發和測試的效率。
內嵌容器的特點
- 獨立性:應用程序包含了所有必要的依賴和服務器配置,能夠獨立運行,而不依賴外部的應用服務器。
- 簡化部署:通過 Maven 或 Gradle 構建后,可以生成一個可執行的 JAR 文件,直接通過命令行運行。
- 一致性:開發、測試和生產環境中的運行環境一致,減少了環境差異帶來的問題。
如何替換默認容器
1.pom形式
如何引入underTow作為內嵌servlet容器
- 在spring-boot-starter-web中排除掉tomcat的jar包
- 引入undertow的依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency><!-- 使用 Undertow 替換掉 Tomcat --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
觀察console
2024-05-17 16:38:26.099 INFO 1108 --- [ main] io.undertow : starting server: Undertow - 2.2.16.Final
2024-05-17 16:38:26.102 INFO 1108 --- [ main] org.xnio : XNIO version 3.8.6.Final
2024-05-17 16:38:26.105 INFO 1108 --- [ main] org.xnio.nio : XNIO NIO Implementation Version 3.8.6.Final
2024-05-17 16:38:26.125 INFO 1108 --- [ main] org.jboss.threads : JBoss Threads version 3.1.0.Final
2024-05-17 16:38:26.162 INFO 1108 --- [ main] o.s.b.w.e.undertow.UndertowWebServer : Undertow started on port(s) 8080 (http)
2024-05-17 16:38:26.168 INFO 1108 --- [ main] c.a.s.SpringBootAnnotationApplication : Started SpringBootAnnotationApplication in 1.179 seconds (JVM running for 1.914)
通過日志觀察,默認內嵌容器已經替換成underTow,同理jetty一樣
2.主動配置
由于SpringBoot在獲取servlet容器是通過ServletWebServerFactory類型來獲取。ServletWebServerFactory一共有三個實現類,分別為JettyServletWebServerFactory
,UndertowServletWebServerFactory
,TomcatServletWebServerFactory
。分別對應jetty,underTow,tomcat。
SpringBoot在AbstractApplicationContext.refresh()方法的onRefresh(),通過 ServletWebServerApplicationContext重寫該方法創建webServer();
protected void onRefresh() {super.onRefresh();try {this.createWebServer();} catch (Throwable var2) {throw new ApplicationContextException("Unable to start web server", var2);}
}
在createWebServer()中有個獲取WebServerFactory方法獲取對應的實現類的方法getWebServerFactory();
protected ServletWebServerFactory getWebServerFactory() {String[] beanNames = this.getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);if (beanNames.length == 0) {throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.");} else if (beanNames.length > 1) {throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));} else {return (ServletWebServerFactory)this.getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);}}
getWebServerFactory(),通過在Spring容器中獲取ServletWebServerFactory類型的bean,如果獲取不到和獲取多個都會拋出異常
所以我們可以通過手動配置ServletWebServerFactory
對應的實現類,以此來切換不同的容器。
- 將tomcat,jetty,undertow的starter都引入到項目中
- 新建配置ServletServerConfig
@Configuration
public class ServletServerConfig {@Beanpublic ServletWebServerFactory underTowServletWebServerFactory(){UndertowServletWebServerFactory undertowServletWebServerFactory = new UndertowServletWebServerFactory();undertowServletWebServerFactory.setPort(8087);return undertowServletWebServerFactory;}//@Beanpublic ServletWebServerFactory tomcatServletWebServerFactory(){TomcatServletWebServerFactory tomcatServletWebServerFactory = new TomcatServletWebServerFactory();tomcatServletWebServerFactory.setPort(8081);return tomcatServletWebServerFactory;}//@Beanpublic ServletWebServerFactory jettyServletWebServerFactory(){JettyServletWebServerFactory jettyServletWebServerFactory = new JettyServletWebServerFactory();jettyServletWebServerFactory.setPort(8086);return jettyServletWebServerFactory;}
}
需要用哪個容器,就把其他兩個容器注釋掉。(不能創建多個ServletWebServerFactory,在getWebServerFactory()中會拋異常)
如何通過配置切換serlvet容器
在主動配置的基礎上,可以通過對config進行改造
- 在application.yaml中配置servlet.server屬性 ,具體1,2,3代表tomcat還是jetty由自己定義
- 利用SpringBoot注解@ConditionalOnProperty注解可以切換servlet容器
servlet:server: 2
@Configuration
public class ServletServerConfig {@Bean@ConditionalOnProperty(name = "servlet.server",havingValue = "1")public ServletWebServerFactory underTowServletWebServerFactory(){UndertowServletWebServerFactory undertowServletWebServerFactory = new UndertowServletWebServerFactory();undertowServletWebServerFactory.setPort(8087);return undertowServletWebServerFactory;}@Bean@ConditionalOnProperty(name = "servlet.server",havingValue = "2")public ServletWebServerFactory tomcatServletWebServerFactory(){TomcatServletWebServerFactory tomcatServletWebServerFactory = new TomcatServletWebServerFactory();tomcatServletWebServerFactory.setPort(8081);return tomcatServletWebServerFactory;}@Bean@ConditionalOnProperty(name = "servlet.server",havingValue = "3")public ServletWebServerFactory jettyServletWebServerFactory(){JettyServletWebServerFactory jettyServletWebServerFactory = new JettyServletWebServerFactory();jettyServletWebServerFactory.setPort(8086);return jettyServletWebServerFactory;}
}
ServletServerConfig中,1表示underTow,2表示tomdat,3,表示jetty。而application.yml中配置的2,則啟動項目,觀察console
2024-05-17 17:14:19.142 INFO 7500 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2024-05-17 17:14:19.148 INFO 7500 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
將配置更改為3
,再次啟動,觀察console
2024-05-17 17:15:01.473 INFO 5260 --- [ main] o.e.jetty.server.AbstractConnector : Started ServerConnector@13579834{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
2024-05-17 17:15:01.473 INFO 5260 --- [ main] o.s.b.web.embedded.jetty.JettyWebServer : Jetty started on port(s) 8080 (http/1.1) with context path '/'