开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 24 天,点击查看活动详情
Spring Boot 中,默认使用嵌入式 Tomcat 作为 Web 容器。
因此,我们开发的 Servlet 应用不需要部署在外部的 Web 容器中,直接通过 java -jar
方式就能运行。
今天,我将为大家介绍一下如何配置嵌入式 Web 容器,以及如何替换默认的 Tomcat 为其他的容器,例如 Jetty。
01-Spring Boot 中配置嵌入式容器
Spring Boot 2与之前版本在接口上发生了变化,所以配置方式根据使用的 Spring Boot 版本不同而分为了两种。 第一种,Spring Boot 2之前的版本,使用 EmbeddedServletContainerCustomizer 接口:
@Component
public class CustomContainer implements EmbeddedServletContainerCustomizer {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setPort(8081);
container.setContextPath("/demo");
}
}
第二中,Spring Boot 2以上的版本,使用 WebServerFactoryCustomizer 接口。
// 第一种
@Component
public class EmbeddedContainerCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
@Override
public void customize(ConfigurableServletWebServerFactory factory) {
factory.setPort(8888);
factory.setContextPath("/demo");
}
}
// 第二种
@Component
public class EmbeddedContainerCustomizer2 implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
factory.setPort(8088);
factory.setContextPath("/demo");
}
}
其中,TomcatServletWebServerFactory 是 ConfigurableServletWebServerFactory 接口的一个实现。
WebServerFactoryCustomizer 是 Spring Boot 定义的一个函数式接口,只有一个 customize 方法。
所有实现了该接口的类,都会被 org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor
处理。
WebServerFactoryCustomizerBeanPostProcessor 是一个 BeanPostProcessor,在 WebServerFactory 类型的 Bean 创建时会执行特殊的逻辑。
LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory) // 从 ApplicationContext 中取出所有相关的 Customizer,
.withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
.invoke((customizer) -> customizer.customize(webServerFactory)); // 执行他们的 customize 方法
02-修改默认的嵌入式容器类型
Spring Boot 默认使用嵌入式 Tomcat 作为 Web 容器。 所以,在 spring-web 中已经引用了 Tomcat 相关的依赖。
如果要替换 Web 容器类型,需要先在 spring-web 中将 Tomcat 相关的依赖移除掉。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 替换底层的 servlet 容器 -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
然后,引入要使用的 Web 容器。例如,使用 Jetty,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
或者使用 Undertow,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
Spring Boot 对 Jetty 和 Undertow 的配置方式与 Tomcat 一样都做了统一的抽象,都可以使用 WebServerFactoryCustomizer 接口来配置。 只不过 Jetty 的配置类是 ConfigurableJettyWebServerFactory 或 JettyServletWebServerFactory;Undertow 的配置类是 ConfigurableUndertowWebServerFactory 或 UndertowServletWebServerFactory。 配置内容也因容器的不同,而略有不同,这里就不再继续展开介绍。
03-以程序方式启动 Tomcat
本节中,我将介绍如何通过程序的方式创建、配置并运行一个 Tomcat。
首先,添加依赖:
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>8.5.24</version>
</dependency>
然后,通过程序创建并启动 Tomcat:
// 创建 Tomcat 实例
Tomcat tomcat = new Tomcat();
// 设置端口号
tomcat.setPort(8081);
tomcat.setHostname("localhost");
String appBase = ".";
tomcat.getHost().setAppBase(appBase);
File docBase = new File(System.getProperty("java.io.tmpdir"));
Context context = tomcat.addContext("", docBase.getAbsolutePath());
// 设置 Servlet
Class servletClass = MyServlet.class;
Tomcat.addServlet(context, servletClass.getSimpleName(), servletClass.getName());
context.addServletMappingDecoded("/my-servlet/*", servletClass.getSimpleName());
// 启动 tomcat
tomcat.start();
我在上面的例子中向 Tomcat 中添加的 Servlet 非常简单,对所有的请求都响应一个 "Ok"。
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(HttpServletResponse.SC_OK);
resp.getWriter().write("Ok");
resp.getWriter().flush();
resp.getWriter().close();
}
}
然后,运行一下程序,访问 http://localhost:8081/my-servlet 就会得到一个 Ok 页面。
04-总结
今天,我介绍了如何配置 Spring Boot 底层适用的 Servlet 容器,然后介绍了如何替换底层的 Servlet 容器为其他类型,例如 Jetty、Undertow。 最后,我介绍了如何通过编程的方式创建并运行 Tomcat。
希望今天的内容能对你有所帮助。