请看原来写的文章:springmvc
@RequestMapping("/{id}")
public String showUserInfo(ModelMap modelMap, @PathVariable("id")Integer id){
Student student = new Student();
student.setId(id);
student.setAge(100);
student.setName("test");
modelMap.addAttribute("name", student.getName());
modelMap.addAttribute("age", student.getAge());
modelMap.addAttribute("id", student.getId());
return "result";
}
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
代码位置:org.springframework.web.servlet.DispatcherServlet#initStrategies
//用于初始化 Spring MVC 的各个策略组件。
protected void initStrategies(ApplicationContext context) {
//初始化处理文件上传的解析器,用于解析请求中的 multipart 数据。
this.initMultipartResolver(context);
//初始化处理国际化的解析器,用于解析请求中的语言区域信息。
this.initLocaleResolver(context);
//初始化处理主题的解析器,用于解析请求中的主题信息。
this.initThemeResolver(context);
//初始化处理器映射器,用于将请求映射到对应的处理器(Controller)。
this.initHandlerMappings(context);
//初始化处理器适配器,用于调用处理器的方法并从中获取 ModelAndView 对象。
this.initHandlerAdapters(context);
//初始化处理器异常解析器,用于处理请求过程中发生的异常。
this.initHandlerExceptionResolvers(context);
//初始化请求到视图名称的转换器,用于将处理器返回的逻辑视图名称转换为实际的视图路径。
this.initRequestToViewNameTranslator(context);
//初始化视图解析器,用于将视图名称解析为具体的视图类型。
this.initViewResolvers(context);
//初始化 FlashMap 管理器,用于处理请求间的数据传递。
this.initFlashMapManager(context);
}
代码位置:org.springframework.context.event.SimpleApplicationEventMulticaster#doInvokeListener
//执行应用程序事件监听器
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
//调用监听器的 并传递当前发生的应用程序事件作为参数。
listener.onApplicationEvent(event);
} catch (ClassCastException var6) {
String msg = var6.getMessage();
if (msg != null && !this.matchesClassCastMessage(msg, event.getClass().getName())) {
throw var6;
}
Log logger = LogFactory.getLog(this.getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, var6);
}
}
}
注意监听器:org.springframework.context.event.SimpleApplicationEventMulticaster#doInvokeListener
由于我们配的视图是:
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
所以解析出来是:
代码位置:org.springframework.beans.factory.BeanFactoryUtils#beansOfTypeIncludingAncestors(org.springframework.beans.factory.ListableBeanFactory, java.lang.Class<T>, boolean, boolean)
最终我们都会调onRefresh()完成初始化。代码位置:org.springframework.web.servlet.FrameworkServlet#initWebApplicationContext
if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
onRefresh(wac);
}
那么spring加载完成后,就是调用的问题,这里注意,会根据不同的调用方式来进行分发,比如http tcp 等的分发方式都不太一样。那最终都会调到doDispatch.
代码位置:org.springframework.web.servlet.DispatcherServlet#doDispatch
//分发方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//初始化请求信息
HttpServletRequest processedRequest = request;
//用于存储根据请求对象匹配到的处理器对象
HandlerExecutionChain mappedHandler = null;
//标识是否已解析多部分请求
boolean multipartRequestParsed = false;
//获取当前WebAsyncManager对象(异步处理)
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
//初始化视图模型
ModelAndView mv = null;
Exception dispatchException = null;
try {
//检查请求是否为多部分请求(文件或),通过检查请求头中的 "Content-Type" 是否以 "multipart/" 开头来判断。
processedRequest = checkMultipart(request);
//判断是否一致,如果是则为true
multipartRequestParsed = (processedRequest != request);
// 获取处理对象
mappedHandler = getHandler(processedRequest);
//为空就是没找着路劲 返回404
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 获取处理对
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 获取请求方法
String method = request.getMethod();
//判断是否为get请求
boolean isGet = "GET".equals(method);
//如果是 或头为HEAD
if (isGet || "HEAD".equals(method)) {
//获取最后时间
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
//新请一个响应并检查,如果不通过直接中止
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//调用处理器的预处理方法 ,如果不通过中止
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 调用适配器
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//检查异步处理是否已经开始
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//设置默认的视图名到ModelAndView中
applyDefaultViewName(processedRequest, mv);
//调用后置处理器方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
//如果出象则创建一个错误的异常
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//返回客户端
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
// 方法检查异步处理是否已经开始
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
//用于在异步处理开始后执行相关的清理操作或其他逻辑处理
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
//用于清理多部分请求中使用的资源
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
接着细节深入
processedRequest = checkMultipart(request);
代码位置:org.springframework.web.servlet.DispatcherServlet#checkMultipart
//将请求转换为分段请求,并使分段解析程序可用。如果未设置多部分解析程序,则只需使用现有请求。
protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
//不为空 且 请求是否是multipart类型
if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
//将请求转换为 multipart类型的请求对象,
if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +
"this typically results from an additional MultipartFilter in web.xml");
}
//检查当前请求是否已经发生过多部分请求解析失败的异常
else if (hasMultipartException(request) ) {
logger.debug("Multipart resolution failed for current request before - " +
"skipping re-resolution for undisturbed error rendering");
}
else {
try {
//转换为HttpServletRequest 并返回
return this.multipartResolver.resolveMultipart(request);
}
catch (MultipartException ex) {
if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
logger.debug("Multipart resolution failed for error dispatch", ex);
// Keep processing error dispatch with regular request handle below
}
else {
throw ex;
}
}
}
}
// If not returned before: return original request.
return request;
}
上面这个方法解析multipart类型的请求。
接着:mappedHandler = getHandler(processedRequest); 这个是用于确定当前请求的处理程
Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//不为空
if (this.handlerMappings != null) {
//循环调用每个 HandlerMapping 的 getHandler(request) 方法,传入当前的 HttpServletRequest 对象作为参数,来获取对应的处理器。
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
当面这个用于获取HandlerExecutionChain,其实就是请求处理器(Handler)的方法。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
根据刚刚获取的处理器进行获取HandlerAdapter,其实就是决定用来调modelandview或其他视图,有很多种,比如:
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
//循环判断是哪种类型匹配,匹配就返回
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
//获取最终的HandlerAdapter
if (ha.supports(handler)) {
return ha;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
mappedHandler.applyPreHandle(processedRequest, response),这个方法用于记录拦截器的执行位置。
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
//调用前置拦截器方法 如果返回值为 false,表示拦截器不允许继续执行后续的处理逻辑
if (!interceptor.preHandle(request, response, this.handler)) {
//方法进行拦截器链的后置处理,并直接返回 false
triggerAfterCompletion(request, response, null);
return false;
}
//记录位置
this.interceptorIndex = i;
}
}
return true;
}
//用于触发拦截器链的后置处理(afterCompletion
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
//不为空
if (!ObjectUtils.isEmpty(interceptors)) {
//循环执行拦截器的后置处理逻辑,通常用于资源清理、日志记录等操作。
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
接受三个参数:processedRequest 是经过前置处理器链处理后的请求对象,response 是响应对象,mappedHandler.getHandler() 是映射到的请求处理器对象。
在执行 handle() 方法时,会根据请求处理器的类型调用相应的处理逻辑。不同的请求处理器可能是不同类型的对象,例如 Controller、HttpRequestHandler 或 HttpMessageConverter 等。
注意:一般HTTP 请求中可以包含多种类型的参数,常见的有以下几种类型:
判断请求参数的方式取决于你使用的服务器端框架或编程语言。大多数框架提供了相应的工具或库来解析和获取请求参数。一般而言,可以通过从请求对象中获取相应的参数来获取请求参数。例如,在 Java 的 Spring 框架中,可以使用 @RequestParam 注解、HttpServletRequest 对象等来获取请求参数。
这个位置非常复杂。有兴趣可以深入。
那么有些同学会疑问,springmvc可以支持哪些参数?
当然上面是我所看源码了解到的,目前有没有其它暂时没看到。可以HandlerMethodArgumentResolver
mappedHandler.applyPostHandle(processedRequest, response, mv);
上面这段是拦截器的一些实现,我们有些请求或不开放的接口权限等可以结合这个来进行拦截。
代码位置:org.springframework.web.servlet.HandlerExecutionChain#applyPostHandle
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
//调用拦截器
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
这个是最后的视图的实现了,但是视图有好多种 如下:
代码位置:org.springframework.web.servlet.DispatcherServlet#processDispatchResult
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
//不为空
if (exception != null) {
//匹配类型为ModelAndViewDefiningException
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
//转换成ModelAndViewDefiningException
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.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
//若请求是异步处理的(Concurrent handling started during a forward),则直接返回,不做后续处理。
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
//不为空打印日志
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
后面就是一些异常和finally的处理,都是清空缓存的一些处理。不细看,有兴趣可以了解一下。
springmvc非常重要,特别源码这块,涉及视图解析以及如何拦截等逻辑,这些核心特别是想在spring方面有所提升的同学,建议可以再细详深入debug一行一行把核心逻辑过一下,真的后面想走得深入或做架构方面及整合一些框架这些流程先后顺序必须懂,否则很容易吃一大亏。当然以上仅是本人看法。
参考文章:
https://www.yii666.com/blog/452442.html
https://blog.csdn.net/weixin_56644618/article/details/127594065
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有