SpringBoot里的Servlet和实现

10世界杯决赛

Servlet

接口,一个规范,

SpringBoot

Spring Boot 是 Spring 的子项目,正如其名字,提供 Spring 的引导( Boot )的功能。

通过 Spring Boot ,开发者可以快速配置 Spring 项目,引入各种 Spring MVC、Spring Transaction、Spring AOP、等等框架,而无需不断重复编写繁重的 Spring 配置,降低了 Spring 的使用成本。

Servlet 和 SpringBoot

搭建一个 SpringBoot 项目:

引入依赖:

org.springframework.boot

spring-boot-starter-web

添加 Controller

@Controller

public class IndexController {

@RequestMapping("/hello")

public String hello(){

return "hello";

}

}

添加启动类

@SpringBootApplication

public class DemoApplication {

public static void main(String[] args) {

SpringApplication.run(DemoApplication.class, args);

}

}

运行DemoApplication.main即可启动一个简单的 Springboot web 项目。

项目是通过一个内嵌的Tomcat容器来提供 web 服务。Tomcat 是 Servlet 容器,SpringBoot 想要使用 Servlet 容器就需要有 servlet 那么 SpringBoot 中有哪些 Servlet?是怎么通过这些 Servlet 来提供 web 服务的呢?

SpringBoot 中的 Servlet

SpringBoot 中涉及到的 Servlet 及它们的关系

HttpServletBean

主要方法:

设置一些配置信息,并提供子类初始化入口。无具体业务逻辑

@Override

public final void init() throws ServletException {

// Set bean properties from init parameters.

PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);

if (!pvs.isEmpty()) {

try {

BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);

ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());

bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));

initBeanWrapper(bw);

bw.setPropertyValues(pvs, true);

}

catch (BeansException ex) {

if (logger.isErrorEnabled()) {

logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);

}

throw ex;

}

}

// Let subclasses do whatever initialization they like.

//增加子类实例化入口

initServletBean();

}

FrameworkServlet

FrameworkServlet 会实现

#doGet(HttpServletRequest request, HttpServletResponse response)

#doPost(HttpServletRequest request, HttpServletResponse response)

#doPut(HttpServletRequest request, HttpServletResponse response)

#doDelete(HttpServletRequest request, HttpServletResponse response)

#doOptions(HttpServletRequest request, HttpServletResponse response)

#doTrace(HttpServletRequest request, HttpServletResponse response)

#service(HttpServletRequest request, HttpServletResponse response)

等方法。而这些实现,最终会调用 #processRequest(HttpServletRequest request, HttpServletResponse response) 方法,处理请求。

@Override

protected void service(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());

if (httpMethod == HttpMethod.PATCH || httpMethod == null) {

processRequest(request, response);

}

else {

super.service(request, response);

}

}

@Override

protected final void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

processRequest(request, response);

}

@Override

protected final void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

processRequest(request, response);

}

@Override

protected final void doPut(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

processRequest(request, response);

}

@Override

protected final void doDelete(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

processRequest(request, response);

}

...

处理请求:

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

// <1> 记录当前时间,用于计算 web 请求的处理时间

long startTime = System.currentTimeMillis();

// <2> 记录异常

Throwable failureCause = null;

LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();

LocaleContext localeContext = buildLocaleContext(request);

RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();

ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

initContextHolders(request, localeContext, requestAttributes);

try {

// 执行真正的逻辑

doService(request, response);

} catch (ServletException | IOException ex) {

failureCause = ex; //

throw ex;

} catch (Throwable ex) {

failureCause = ex; //

throw new NestedServletException("Request processing failed", ex);

} finally {

resetContextHolders(request, previousLocaleContext, previousAttributes);

if (requestAttributes != null) {

requestAttributes.requestCompleted();

}

// 打印请求日志,并且日志级别为 DEBUG

logResult(request, response, failureCause, asyncManager);

// 发布 ServletRequestHandledEvent 事件

publishRequestHandledEvent(request, response, startTime, failureCause);

}

}

//抽象类给子类实现

protected abstract void doService(HttpServletRequest request, HttpServletResponse response)

throws Exception;

DispatcherServlet

doService

#doService(HttpServletRequest request, HttpServletResponse response) 方法,DispatcherServlet 的处理请求的入口方法,代码如下:

// DispatcherServlet.java

@Override

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {

logRequest(request);

// Keep a snapshot of the request attributes in case of an include,

// to be able to restore the original attributes after the include.

Map attributesSnapshot = null;

if (WebUtils.isIncludeRequest(request)) {

attributesSnapshot = new HashMap<>();

Enumeration attrNames = request.getAttributeNames();

while (attrNames.hasMoreElements()) {

String attrName = (String) attrNames.nextElement();

if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {

attributesSnapshot.put(attrName, request.getAttribute(attrName));

}

}

}

// Make framework objects available to handlers and view objects.

// 设置 Spring 框架中的常用对象到 request 属性中

request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());

request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);

request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);

request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

...

try {

// 执行请求的分发

doDispatch(request, response);

} finally {

if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {

// Restore the original attribute snapshot, in case of an include.

if (attributesSnapshot != null) {

restoreAttributesAfterInclude(request, attributesSnapshot);

}

}

}

}

doDispatch

#doDispatch(HttpServletRequest request, HttpServletResponse response) 方法,执行请求的分发。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

HttpServletRequest processedRequest = request;

HandlerExecutionChain mappedHandler = null;

boolean multipartRequestParsed = false;

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

try {

ModelAndView mv = null;

Exception dispatchException = null;

try {

processedRequest = checkMultipart(request);

multipartRequestParsed = (processedRequest != request);

// <2> 映射处理器

//获得请求对应的 HandlerExecutionChain 对象

mappedHandler = getHandler(processedRequest);

if (mappedHandler == null) { // 如果获取不到,则根据配置抛出异常或返回 404 错误

noHandlerFound(processedRequest, response);

return;

}

// <3> 处理器适配器

// 获得当前 handler 对应的 HandlerAdapter 对象

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// last-modified

String method = request.getMethod();

boolean isGet = "GET".equals(method);

if (isGet || "HEAD".equals(method)) {

long lastModified = ha.getLastModified(request, mappedHandler.getHandler());

if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {

return;

}

}

// 前置处理 拦截器

if (!mappedHandler.applyPreHandle(processedRequest, response)) {

return;

}

// <4> 调用处理器方法

// 真正的调用 handler 方法,并返回视图

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {

return;

}

// 视图

applyDefaultViewName(processedRequest, mv);

// 后置处理 拦截器

mappedHandler.applyPostHandle(processedRequest, response, mv);

} catch (Exception ex) {

dispatchException = ex; // 记录异常

} catch (Throwable err) {

dispatchException = new NestedServletException("Handler dispatch failed", err); // <10> 记录异常

}

// 处理正常和异常的请求调用结果。

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

} catch (Exception ex) {

...

}

...

}

processDispatchResult

#processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) 方法,处理正常和异常的请求调用结果。代码如下:

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,

@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,

@Nullable Exception exception) throws Exception {

// 标记,是否是生成的 ModelAndView 对象

boolean errorView = false;

//如果是否异常的结果

if (exception != null) {

if (exception instanceof ModelAndViewDefiningException) {

logger.debug("ModelAndViewDefiningException encountered", exception);

mv = ((ModelAndViewDefiningException) exception).getModelAndView();

} else {

Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);

mv = processHandlerException(request, response, handler, exception);

errorView = (mv != null);

}

}

if (mv != null && !mv.wasCleared()) {

// 渲染页面

render(mv, request, response);

if (errorView) {

WebUtils.clearErrorRequestAttributes(request);

}

} else {

if (logger.isTraceEnabled()) {

logger.trace("No view rendering, null ModelAndView returned.");

}

}

...

}

render

#render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response)

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {

// Determine locale for request and apply it to the response.

Locale locale =

(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());

response.setLocale(locale);

View view;

String viewName = mv.getViewName();

if (viewName != null) {

//<5> 解析视图

// 视图解析器ViewResolver

view = resolveViewName(viewName, mv.getModelInternal(), locale, request);

if (view == null) {

throw new ServletException("Could not resolve view with name '" + mv.getViewName() +

"' in servlet with name '" + getServletName() + "'");

}

}

else {

// No need to lookup: the ModelAndView object contains the actual View object.

view = mv.getView();

if (view == null) {

throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +

"View object in servlet with name '" + getServletName() + "'");

}

}

// Delegate to the View object for rendering.

if (logger.isTraceEnabled()) {

logger.trace("Rendering view [" + view + "] ");

}

try {

if (mv.getStatus() != null) {

response.setStatus(mv.getStatus().value());

}

//<6> 渲染视图

//视图渲染

view.render(mv.getModelInternal(), request, response);

}

catch (Exception ex) {

if (logger.isDebugEnabled()) {

logger.debug("Error rendering view [" + view + "]", ex);

}

throw ex;

}

}

至此,对照图中的一个请求的处理流程在 DispatcherServlet 中的流转结束。

End