1. 如何找到tomcat
ServletWebServerFactoryConfiguration下面有三个EmbeddedTomcat,EmbeddedJetty,EmbeddedUndertow注解为@Configuratio的类,但是它们有condition, 只有满足条件才会被注册,因为spring-boot-starter-web项目中的pom.xml默认使用tomcat
所以只有tomcatServletWebServerFactory的注解@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })满足条件而被注册,ServletWebServerApplicationContext.getWebServerFactory会得到TomcatServletWebServerFactory
2. 如何不使用server.xml
TomcatServletWebServerFactory.getWebServer会获得WebServer,它不需server.xml,而是在getWebServer方法中通过硬编码提供的默认配置构造了Connector,Host,Engine等实例。
3. 如何不使用web.xml配置servlet,filter,listener
TomcatServletWebServerFactory.getWebServer方法中会new一个Tomcat,它是apache提供的,可以在没有web.xml的时候来启动tomcat容器。TomcatWebServer.initialize()会调用{this.tomcat.start()}来启动tomcat容器的线程。
DispatcherServletAutoConfiguration$DispatcherServletConfiguration.dispatcherServlet()会自动注册spring web的前端控制器dispatcherServlet到容器中。
tomcat的映射原理是ApplicationContextFacade根据url来找到对应的servlet,所以spring要通过ServletRegistrationBean.addRegistration方法将dispatcherServlet注册进tomcat的ApplicationContextFacade容器。
ServletRegistrationBean里有dispatcher的默认映射配置为/*, 它会把该映射设置到apache的ApplicationServletRegistration.addMapping中。至此tomcat可以处理/*的请求。
4. 如何使用view(jsp,thymeleaf)
如果你引入thymeleaf jar,则ThymeleafAutoConfiguration的条件配置满足,会自动配置以下主要的thymeleaf功能类:
ThymeleafProperties:通过application.properties里的前辍为"spring.thymeleaf"来设置ThymeleafProperties类。
ThymeleafViewResolver:将逻辑视图名称解析为Thymeleaf模板视图。
SpringTemplateEngine:处理模板并渲染结果。
TemplateResolver:加载Thymeleaf模板。
5. 流程:
所有请求都会被dispatcherServlet捕获,spring将apache的request,response封装成ServletWebRequest,
再ServletInvocableHandlerMethod.invokeAndHandle(ServletWebRequest),该方法有两个功能invoke和handle:
1). invoke是将请求分派到具体的spring mvc的controller的方法上去执行。
2). handle是将invoke生成的model和view渲染成html输出。具体过程如下:
不同的view有不同的HandlerMethodReturnValueHandler,RequestMappingHandlerAdapter.getDefaultReturnValueHandlers()里有15个默认ReturnValueHandler。遍历DefaultReturnValueHandlers找到第一满足HandlerMethodReturnValueHandler.supportsReturnType==view的handler来处理,如果action返回字符串,则交由ViewNameMethodReturnValueHandler来处理,handler仅作ModelAndViewContainer.setViewName(viewName);处理。
接下来RequestMappingHandlerAdapter.getModelAndView(ModelAndViewContainer)更新model并获取ModelAndView{viewName和model}对象。
接下来DispatcherServlet.render(ModelAndView, request, response);使用model和template来渲染view。ContentNegotiatingViewResolver它是一个总控,它会resolveViewName(viewName)找到对应的View,至此template还没有加载。
接下来View.render(model, request, response); 会调用SpringTemplateEngine.process(templateName, context, response.getWriter()); 在此方法中主要是TemplateResolution.templateResource加载template,并对里面的tag进行动态解析,最后使用response.getWriter()输出。
6. 扩展自定义servlet
@Configuration
public class WebMvcConfig {
@Bean
public ServletRegistrationBean
return new ServletRegistrationBean
}
}
class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().append("hello servlet").flush();
}
}