发表于: 2020-08-12 22:21:42

1 2296


今天完成的事情

1. SpringMVC


收获

1. Servlet 是 Java 应用程序的基础

Tomcat Web 服务器每个 HTTP 请求都由 Java Servlet 处理。Spring Web 应用的入口是一个 Servlet。

一个 Servlet 只能接受一个 HTTP 请求,然后发回一个响应。


2. Servlet 如何工作

在 Servlet1.1 的时候引入了 JSP,这个时候 JSP 内部混合了 Java 与前端的 html、css 等代码。一个 JSP 文件运行的时候就是一个 Servlet,对应一个页面(我想 JSP 内部肯定是可以写多个页面的,但是可能是太复杂了,不好管理。大概相当于我们现在把所有的 JSP 页面都写在一个文件里,然后通过  model 里面的参数判定要显示哪一页)。

当我们需要一个完善的网站的时候我们就需要写非常多的 JSP 页面,内部有大量的重复代码(我的猜测是每个 JSP 内部都要自己解析 HTTP 请求获取参数信息然后连接数据库等···),并且要配置一个很复杂的 web.xml 让容器把每个 JSP 都加载生成对应的 Servlet(我想配置文件里面有每个 JSP 页面对应的 url 路径等信息)。



3. SpringMVC 做了什么

a,把 HTTP 请求映射到某个处理方法(通过 HandlerMapping 来找到对应的处理器下的方法)

b,把 HTTP 请求数据解析为一个对象(使用时我们也常用到 HttpServletRequest 等对象,或者把前端表单反序列化为一个类)

c,集成模型、视图和控制器(引入 MVC 工作流,按照名称解析视图,允许我们使用不同的模板引擎来处理视图)

d,从对象生成响应的数据


SpringMVC 运行之后在容器内生成了一个 DispatcherServlet,这个 Servlet 的根路径由我们在 web.xml 里面定义,例如:

<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

所有的请求都交给我们写的 SpringMVC 应用来处理。

又如:

<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/ptteng/*</url-pattern>
</servlet-mapping>

/ptteng 路径下的请求都交给我们写的名为 springmvc 的 DispatcherServlet 来处理。


另外 DispatcherServlet 是可以扩展的,比如我们可以通过使用 Apache Commons 来使用文件上传,使用 LocalResolver 实现解决语言环境的问题。


4. SpringMVC 中的 Servlet 调用链


Servlet 中的 sevice 方法负责请求处理。这些方法在 HttpServlet 中被重写。

HttpServlet 中通过区分不同的请求类型去采取不同的动作,doGet doPost 这些方法也在 FrameworkServlet 中被重写。


httpServletBean、FrameworkServlet 和 DispatcherServlet 属于 Spring 新增的处理类。


其中 HttpServletBean 是第一个 Spring 类。负责从 web.xml 或者 WebApplicationInitializer 接收到的 Servlet init-param 值来注入 bean 属性。

在请求应用程序的情况下,根据 HTTP 请求去调用 HttpServlet 的 doGet doPost doDelete 等方法


FrameworkServlet 继承了 Servlet 与 Web 应用程序上下文,取得 LocaleContext 后实例化 context class,否则使用默认的 XmlWebApplicationContext。

总之 SpringMVC 中的 applicationContext 的初始化工作就是 FrameworkServlet 来完成的。


DispatcherServlet 统一请求处理

在 HttpServlet.service() 中已经能够根据 HTTP 请求类型来选择处理方法了,但是在 SpringMVC 中,请求类型只是我们用来映射到处理方法的参数之一。

因此我们在 FrameworkServlet 中可以看到 doGet doPost 方法最后还是都交给 processRequest() 方法去执行。

@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

processRequest(request, response);
}

/**
* Delegate POST requests to {@link #processRequest}.
* @see #doService
*/
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

processRequest(request, response);
}

/**
* Delegate PUT requests to {@link #processRequest}.
* @see #doService
*/
@Override
protected final void doPut(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

processRequest(request, response);
}

/**
* Delegate DELETE requests to {@link #processRequest}.
* @see #doService
*/
@Override
protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

processRequest(request, response);
}

而 processRequest 方法又去调用 doService() 方法

/**
* Process this request, publishing an event regardless of the outcome.
* <p>The actual event handling is performed by the abstract
* {@link #doService} template method.
*/
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

long startTime = System.currentTimeMillis();
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();
     }
logResult(request, response, failureCause, asyncManager);
publishRequestHandledEvent(request, response, startTime, failureCause);
  }
}


最后 doService 方法由 DispatcherServlet 去实现。

在 doServie 方法中网请求里面增加了一些东西(web 应用程序上下文等),丰富了请求对象的内容,随后交给了 doDispatcher() 方法。


doDispatcher() 方法的主要目的是做请求的分发,为请求找到一个合适的处理程序,并且把请求的参数给它。

为了找到匹配的处理方法,Spring 会检查 HandlerMapping 接口的注册实现。比如 RequestMappingHandlerMapping 负责把请求映射给 @Controller 注解的类中的 带 @RequestMapping 的方法。


映射完成后,对应的方法开始处理请求。处理完之后如果返回的是页面那么就交给对应的视图解析器去渲染。

如果处理方法被 @RequestBody 注解那么就会把结果直接转换为 HTTP 响应。


明天的计划:

1. 准备复盘资料


返回列表 返回列表
评论

    分享到