前言
前文中提到了Tomcat的嵌入式部署,在spring web应用中,默认使用Tomcat嵌入式进行部署。引入spring-boot-starter-web依赖以后,会将相关联的spring-boot-starter-tomcat-tomcat一并引入。
引用过程
WebServer接口
spring定义了web容器接口【WebServer】,支持多种实现进行嵌入式部署,如下所示
初始化嵌入式Tomcat
springboot web应用启动时,初始化Tomcat嵌入式容器。
源代码TomcatServletWebServerFactory.getWebServer()里,Tomcat容器和上一章里的嵌入式示例初始化过程基本一致
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null) ? this.baseDirectory
: createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);
}
网络请求
加载spring里的DispatchServlet,用于转发Tomcat容器传过来的网络请求;
@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServletRegistrationBean dispatcherServletRegistration(
DispatcherServlet dispatcherServlet) {
DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(
dispatcherServlet, this.webMvcProperties.getServlet().getPath());
registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
registration.setLoadOnStartup(
this.webMvcProperties.getServlet().getLoadOnStartup());
if (this.multipartConfig != null) {
registration.setMultipartConfig(this.multipartConfig);
}
return registration;
}
自定义Servlet
使用@WebServlet注册,需要在Servlet类上使用该注解即可,但是需要在@Configuration类中使用Spring Boot提供的注解@ServletComponentScan扫描注册相应的Servlet。
@WebServlet("/servlet")
public class ServletCtrl extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
PrintWriter out = resp.getWriter();
// 输出一个网页
out.println("<!DOCTYPE html><html><head>");
out.println("<meta charset="UTF-8" />");
out.println("<title></title>");
out.println("</head><body>");
// 编辑网页内容
out.println("<h1>hello tomcat.</h1>");
out.println("</body></html>");
}
}
如何注册
在TomcatStarter.onStartup(...)方法中,会扫描实现接口【Servlet】的类,将之托管到Spring上下文中。
绑定StandardWrapper
在之前的章节中,我们已经了解到,每个Servlet都会与一个StandardWrapper绑定,融入tomcat容器系统之中,tomcat根据servlet映射进行请求分发。上面我们实现了一个自定义的Servlet【ServletCtrl】,在启动阶段被Spring动态注册【DynamicRegistrationBean.register(...)】,然后绑定Wrapper。