【Spring MVC研究】MVC如何浏览器请求(service方法)

文章目录

  • 1. DispatcherServlet 的 service 方法
    • 1.1. processRequest 方法
    • 1.2. doService 方法

背景:平时我们学习 MVC 重点关注的时DispatcherServlet 的 doDispatcher 方法,但是在 doDispatcher 方法之前 还有请求处理的前置过程,这个过程作为一个高级程序员是必须要了解的。

1. DispatcherServlet 的 service 方法

DispatcherServlet的继承关系如下图:

因为是 Servlet,自然看它的 service 方法

    public void service(ServletRequest req, ServletResponse res)throws ServletException, IOException{HttpServletRequest  request;HttpServletResponse response;if (!(req instanceof HttpServletRequest &&res instanceof HttpServletResponse)) {throw new ServletException("non-HTTP request or response");}request = (HttpServletRequest) req;response = (HttpServletResponse) res;service(request, response);}

为了处理 patch 请求

	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);}}

各种请求类型分发:

    protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException{String method = req.getMethod();if (method.equals(METHOD_GET)) {long lastModified = getLastModified(req);if (lastModified == -1) {// servlet doesn't support if-modified-since, no reason// to go through further expensive logicdoGet(req, resp);} else {long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);if (ifModifiedSince < lastModified) {// If the servlet mod time is later, call doGet()// Round down to the nearest second for a proper compare// A ifModifiedSince of -1 will always be lessmaybeSetLastModified(resp, lastModified);doGet(req, resp);} else {resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);}}} else if (method.equals(METHOD_HEAD)) {long lastModified = getLastModified(req);maybeSetLastModified(resp, lastModified);doHead(req, resp);} else if (method.equals(METHOD_POST)) {doPost(req, resp);} else if (method.equals(METHOD_PUT)) {doPut(req, resp);} else if (method.equals(METHOD_DELETE)) {doDelete(req, resp);} else if (method.equals(METHOD_OPTIONS)) {doOptions(req,resp);} else if (method.equals(METHOD_TRACE)) {doTrace(req,resp);} else {//// Note that this means NO servlet supports whatever// method was requested, anywhere on this server.//String errMsg = lStrings.getString("http.method_not_implemented");Object[] errArgs = new Object[1];rArgs[0] = method;errMsg = MessageFormat.format(errMsg, errArgs);resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);}}

各种 doXxx 方法会流转到,以下以 doGet 为例子,其它类似。特殊的请求方法有特殊处理,我们不用管。

	@Overrideprotected final void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}

继续看 processRequest 方法

1.1. processRequest 方法

	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {long startTime = System.currentTimeMillis();Throwable failureCause = null;// <1> LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();LocaleContext localeContext = buildLocaleContext(request);// <2> RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);// <3> WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());// <4> initContextHolders(request, localeContext, requestAttributes);try {// <5> doService(request, response);}catch (ServletException | IOException ex) {failureCause = ex;throw ex;}catch (Throwable ex) {failureCause = ex;throw new NestedServletException("Request processing failed", ex);}// <6> finally {resetContextHolders(request, previousLocaleContext, previousAttributes);if (requestAttributes != null) {requestAttributes.requestCompleted();}logResult(request, response, failureCause, asyncManager);publishRequestHandledEvent(request, response, startTime, failureCause);}}
  • 在<1>处,获取之前的语言上下文。然后构建本次的语言上下文。LocaleContext

语言上下文是可以继承的。把之前的保存下来,在请求处理完之后要“还原”。

  • 在<2>处,获取之前的“请求属性上下文”RequestAttributes,具体实现类是:ServletRequestAttributes

这个上下文不能继承,必须是当次请求的。

  • 在<3>处,获取“Web 的异步管理器”

此处与异步请求相关:RequestBindingInterceptor

  • 在<4>处,绑定 2 个上下文。把 LocaleContext 绑定到LocaleContextHolder中,把 ServletRequestAttributes 绑定到RequestContextHolder

这个上下文非常有用,Web 的很多工具类使用到这个上下文来简化编程。不需要传参数request,直接在任意位置获取request。

  • 在<5>处,具体如何处理请求。后续会详细分析
  • 在<6>处,清尾操作。

1、把之前的2个上下文还原。
2、记录请求的日志(此处是否就是框架提供的打印响应日志的地方?)
3、发布事件(请求处理完成事件ServletRequestHandledEvent)

1.2. doService 方法

	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<String, Object> 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.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());if (this.flashMapManager != null) {FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);if (inputFlashMap != null) {request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));}request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);}RequestPath previousRequestPath = null;if (this.parseRequestPath) {previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);ServletRequestPathUtils.parseAndCache(request);}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);}}if (this.parseRequestPath) {ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);}}}

不详细解释了,主要是把 Spring 框架的一些组件放入到request的请求属性中。在后续可以根据 request 拿出 Spring 框架的组件。比如设置了如下的内容:

  • Web 的上下文
  • 本地语言解析器
  • 主题解析器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/129189.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

electron.js入门-为生产环境构建应用程序

在本章中&#xff0c;我们将学习如何使用可执行文件生成生产应用程序&#xff1b;为此&#xff0c;我们将使用以下软件包&#xff1a; https://www.electron.build/ 需要注意的是&#xff0c;当您有兴趣生成应用程序的可执行文件时&#xff0c;必须在每个Electron.js项目中安装…

linux centos Python + Selenium+Chrome自动化测试环境搭建?

在 CentOS 系统上搭建 Python Selenium Chrome 自动化测试环境&#xff0c;需要执行以下步骤&#xff1a; 1、安装 Python CentOS 7 自带的 Python 版本较老&#xff0c;建议使用 EPEL 库或源码安装 Python 3。例如&#xff0c;使用 EPEL 库安装 Python 3&#xff1a; sud…

Java 线程的生命周期

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开兴好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…

国内就能使用的chatgpt网页版,包含AIGC应用工具

Chatgpt的出现在多个领域带来了重要的影响。它能够显著提高我们的工作效率&#xff0c;无论是编写文案代码还是回答常见问题&#xff0c;都能在短时间内完成任务。通过Chatgpt&#xff0c;我们能够迅速获取所需答案。随着人工智能技术的不断发展&#xff0c;相信在未来AI能够带…

知识图谱1_2——下载neo4j客户端

客户端下载 这里展现一种通过客户端进行操作的方法 https://neo4j.com/download/ 下载desktop客户端 填写完成后开始下载 下载完成后&#xff0c;在命令行输入 chmod x <文件名> #给予文件权限 sudo add-apt-repository universe #安装.appimage所需的包fuse&#x…

3分钟基于Chat GPT完成工作中的小程序

1. 写在前面 GPT自从去年爆发以来&#xff0c;各大公司在大模型方面持续发力&#xff0c;行业大模型也如雨后春笋一般发展迅速&#xff0c;日常工作中比较多的应用场景还是问答模式&#xff0c;作为写程序的辅助也偶尔使用。今天看到一篇翻译的博客“我用 ChatGPT&#xff0c;…

基于正点原子alpha开发板的第三篇系统移植

系统移植的三大步骤如下&#xff1a; 系统uboot移植系统linux移植系统rootfs制作 一言难尽&#xff0c;踩了不少坑&#xff0c;当时只是想学习驱动开发&#xff0c;发现必须要将第三篇系统移植弄好才可以学习后面驱动&#xff0c;现将移植好的文件分享出来&#xff1a; 仓库&…

ViewPager、RecycleView实现轮播图

1.ViewPager实现轮播图形效果。 1&#xff09;layout中&#xff0c;PageIndicatorView轮播的View <RelativeLayoutandroid:layout_width"match_parent"android:layout_height"200dp"android:orientation"vertical"><androidx.viewpager…

Windows安装人大金仓数据库问题解决

一、安装包、授权文件下载 官网下载windows对应的安装包 下载授权文件 二、安装 &#xff08;1&#xff09;将下载的授权文件包解压待用 &#xff08;2&#xff09;将下载好的.iso安装程序解压&#xff0c;使用管理员身份运行安装程序&#xff0c;一路下一步&#xff0c;直…

Android Studio编写xml布局不提示控件的部分属性问题的解决

最近突然发现Android Studio编写xml&#xff0c;发现有一部分控件的属性没有了代码提示&#xff0c;主要体现为id,margin等属性不再有代码提示&#xff0c;如下图。 但是手动输入仍然有效。然后删掉Android Sdk重新回来还是发现有问题&#xff0c;导一个之前的旧项目进来&#…

Flex 布局中避免子元素高度被撑高

Flex 布局中避免子元素高度被撑高 Flex 布局中子元素高度容易被最高元素撑高&#xff0c;使用 align-self 可避免。 之前&#xff1a; 之后&#xff1a; /* 此处是居中对齐&#xff0c;也可使用 flex-start 顶部对齐 */ align-self: center;

使用hugo+github搭建免费个人博客

使用hugogithub搭建免费个人博客 前提条件 win11电脑一台电脑安装了git电脑安装了hugogithub账号一个 个人博客本地搭建 初始化一个博客 打开cmd窗口&#xff0c;使用hugo新建一个博客工程 hugo new site blogtest下载主题 主题官网&#xff1a;themes.gohugo.io 在上面…