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

news2025/1/13 10:28:46

文章目录

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

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

1. DispatcherServlet 的 service 方法

DispatcherServlet�的继承关系如下图:
image.png
因为是 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 logic
                doGet(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 less
                    maybeSetLastModified(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 为例子,其它类似。特殊的请求方法有特殊处理,我们不用管。

	@Override
	protected 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.coloradmin.cn/o/1071070.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

B站涨粉,UP主涨粉技巧有哪些?

B 站作为深受年轻人喜爱的社交媒体平台&#xff0c;是一个不断生产优质内容的多元化文化社区&#xff0c;有不少视频出圈。随着视频行业的成熟发展&#xff0c;视频创作者们的竞争愈发激烈&#xff0c;不少创作者有涨粉难&#xff0c;曝光差的困扰。而UP主连续不断的涨粉不仅取…

CS5210芯片设计|CS5210设计方案|HDMI转VGA方案|

CS5210方案应用&#xff0c;CS5210方案设计&#xff0c;HDMI转VGA方案&#xff0c;国产集睿致远研发CS5210 HDMI到VGA转换器结合了HDMI输入接口和模拟RGB DAC输出。支持内部LDO&#xff0c;节省成本&#xff0c;优化电路板空间。CS5210适用于各种市场和显示应用程序&#xff0c…

ToBeWritten之车联网安全中常见的TOP 10漏洞

也许每个人出生的时候都以为这世界都是为他一个人而存在的&#xff0c;当他发现自己错的时候&#xff0c;他便开始长大 少走了弯路&#xff0c;也就错过了风景&#xff0c;无论如何&#xff0c;感谢经历 转移发布平台通知&#xff1a;将不再在CSDN博客发布新文章&#xff0c;敬…

MySql 终端常用指令

一、开发背景 利用数据库实现数据的增删改查 二、开发环境 Window10 mysql-8.0.33-win64 三、实现步骤 1、管理员模式打开终端 2、登录数据库&#xff08;停止 开启 登录&#xff09; 具体指令参考 MySql 安装篇 ​​​​​​​ ​​…

Redis中zSet类型的操作

一、什么是zSet zSet是一种特殊的set集合&#xff0c;它的值不能重复&#xff0c;但会对值进行排序。它有个score值&#xff0c;按照Score值从小到大进行排序。score称为分值&#xff0c;它的值是任意正浮点数。数值越小的排序越靠前。如果score相同&#xff0c;则按值的编…

NPM使用

nodejs 安装查看&#xff1a;windows11 安装Nodejs-CSDN博客 一、初始化项目 1、创建文件夹 E:\vue\projectCode\npm-demo 2、打开cmd 进入E:\vue\projectCode\npm-demo目录输入cmd 点击回车 3、先看看npm命令是否可用 npm -v 4、初始化项目 npm init package name: (npm…

动态内存管理函数(malloc,calloc,realloc,free)

动态内存函数 1.1malloc和free C语言提供了一个动态内存开辟的函数&#xff1a; void* malloc (size_t size); 这个函数向内存申请一块连续可用的空间&#xff0c;并返回指向这块空间的指针。 如果开辟成功&#xff0c;则返回一个指向开辟好空间的指针。如果开辟失败&#…

基于YOLOv8模型的120类狗狗目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型的120类狗狗目标检测系统可用于日常生活中检测与定位车辆目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检测算法训练数…

CMYK to RGBA

1、 算法原理 我们首先来看算法原理: 显而易见,CMYK是存储起来的四个值,通过变换可以转换成RGBA值,其中A值始终为255 2、原始代码 // The original code uses a macro UNROLL8 to unroll code and // each iteration processes eight pixels. // // The macro actually…

Spring的AOP开发-AOP简介

目录 AOP简介 AOP概念 AOP思想的实现方案 模拟AOP的基础代码 AOP相关概念 AOP简介 AOP概念 AOP&#xff0c;Aspect Oriented Programming&#xff0c;面向切面编程&#xff0c;是对面向对象编程OOP的生化&#xff0c;OOP是纵向对一个事务的抽象&#xff0c;一个对象包括静…

AIGC之下的创意革命,每个人都是文明的设计师

创意&#xff0c;人类文明的灵魂和火花。人类族群进入文明社会以来&#xff0c;创作基本由少数精英主导&#xff0c;以孔子为代表的东方教育家、哲学家提出由“学在民间”替代“学在官府”的知识传播体系也并未得到真正构建&#xff0c;作品一贯通过有限的渠道传播&#xff0c;…

rsync 远程同步实现快速、安全、高效的异地备份

目录 1 rsync 远程同步 1.1 rsync是什么&#xff1f; 1.2 rsync同步方式 1.3 rsync的特性 1.4 rsync的应用场景 1.5 rsync与cp、scp对比 1.6 rsync同步源 2 配置rsync源服务器 2.1 建立/etc/rsyncd.conf 配置文件 3 发起端 4 发起端配置 rsyncinotify 4.1 修改rsync…

VB编程实现股票量化交易之K线图显示

最近在一个朋友的推荐下&#xff0c;开始研究股票的量化交易系统的开发&#xff0c;这里除了股票数据接口 要实现量化交易不难&#xff0c;基本点就是要有股票数据接口和股票交易接口&#xff0c;还有一些针对指标的策略算法。 Private Function CursorInfo(x As Integer, y A…

java:代理模式

概念代理模式 概念&#xff1a; 真实对象&#xff1a;被代理的对象&#xff0c;背景的联想总部代理对象&#xff1a;也就是那个西安联想代理商代理模式&#xff1a;代理对象代理真实对象&#xff0c;达到增强真实对象功能的目的 实现方式&#xff1a; 静态代理&#xff1a;有一…

vuejs中使用axios时如何追加数据

前言 在vuejs中使用axios时&#xff0c;有时候需要追加数据,比如,移动端下拉触底加载,分页加载,滑动滚动条,等等,这时候就需要追加数据了,下面我们来演示下. 代码演示 <template><div><div><el-button type"primary" click"handleBtnGetJ…

AK F.*ing leetcode 流浪计划之最近公共祖先(倍增算法)

欢迎关注更多精彩 关注我&#xff0c;学习常用算法与数据结构&#xff0c;一题多解&#xff0c;降维打击。 本期话题&#xff1a;在树上查找2个结点的最近公共祖先 问题提出 最近公共祖先定义 最近公共祖先简称 LCA&#xff08;Lowest Common Ancestor&#xff09;。两个节…

STM32MP157汇编流水灯

.text .global _start _start: /* 使能GPIOE、GPIOF寄存器 RCC_MP_AHB4ENSETR * 基地址: 0x50000000 偏移地址: 0xA28 0x50000A28* RCC_MP_AHB4ENSETR[4]->1 RCC_MP_AHB4ENSETR[5]->1*/ LDR R0,0x50000A28LDR R1,[R0]ORR R1,R1,#(0x1<<4)STR R1,[R0]LDR R0,0x…

前端day23--JS进阶(作用域,垃圾回收机制,闭包,剩余参数,箭头函数,解构)

目录 作用域 局部作用域 函数作用域 块作用域 全局作用域 作用域链 JS垃圾回收机制 垃圾回收机制算法说明&#xff1a; 引用计数法(了解)&#xff1a; 标记清除法&#xff1a; 闭包 为什么要有闭包&#xff1f; 闭包的风险→内存泄漏 变量提升 函数进阶 函数提升…

前端uniapp如何修改下拉框uni-data-select下面的uni-icons插件自带的图片【修改uniapp自带源码图片/图标】

目录 未改前图片未改前源码未改前通过top和bottom 和修改后图片转在线base64大功告成最后 未改前图片 未改前源码 然后注释掉插件带的代码&#xff0c;下面要的 未改前通过top和bottom 和修改后 找到uni-icons源码插件里面样式 图片转在线base64 地址 https://the-x.cn/b…

防火墙是什么?F5保护Web应用的思路解读

Web 应用防火墙 (WAF) 是保护 Web 应用的必要措施。如今&#xff0c;WAF 需要在部署环境不断扩展但人员技能有限的情况下&#xff0c;保护数量日益增长的应用。那么防火墙是什么&#xff1f;作为一家提供多云应用安全和应用交付的公司&#xff0c;F5为保护Web应用又打造出哪些产…