水煮Tomcat(七)– SpringBoot与嵌入式

34 阅读1分钟

前言

前文中提到了Tomcat的嵌入式部署,在spring web应用中,默认使用Tomcat嵌入式进行部署。引入spring-boot-starter-web依赖以后,会将相关联的spring-boot-starter-tomcat-tomcat一并引入。

引用过程

WebServer接口

spring定义了web容器接口【WebServer】,支持多种实现进行嵌入式部署,如下所示
image.png

初始化嵌入式Tomcat

springboot web应用启动时,初始化Tomcat嵌入式容器。
image.png
源代码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上下文中。
image.png

绑定StandardWrapper

在之前的章节中,我们已经了解到,每个Servlet都会与一个StandardWrapper绑定,融入tomcat容器系统之中,tomcat根据servlet映射进行请求分发。上面我们实现了一个自定义的Servlet【ServletCtrl】,在启动阶段被Spring动态注册【DynamicRegistrationBean.register(...)】,然后绑定Wrapper。
image.png

请求响应

image.png