mvc源码

本文详细介绍了Spring MVC的核心组件,包括DispatcherServlet、九大组件的作用和流程,如HandlerMapping、HandlerAdapter、异常解析等,揭示了请求从入口到处理再到响应的完整过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.请求入口 DispatcherServlet

在这里插入图片描述

在这里插入图片描述
流程:

1、给Web项目中配置一个 DispatcherServlet,拦截 / 请求

2、初始化的时候 DispatcherServlet 会启动IOC容器,而且会 初始化他底层的九大组件

3、请求到来的时候,Tomcat找到 DispatcherServlet 能处理请求,交给他,DispatcherServlet调用底层的九大组件结合容器、自动装配、反射等功能进行请求处理

2.九大组件

protected void initStrategies(ApplicationContext context) {
        this.initMultipartResolver(context);
        this.initLocaleResolver(context);
        this.initThemeResolver(context);
        this.initHandlerMappings(context);
        this.initHandlerAdapters(context);
        this.initHandlerExceptionResolvers(context);
        this.initRequestToViewNameTranslator(context);
        this.initViewResolvers(context);
        this.initFlashMapManager(context);
    }
//全是接口
initMultipartResolver(context);

##以下都有默认功能
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
  • MultipartResolver:文件上传解析器。
    从容器中获取MultipartResolver类型的,并且名字叫multipartResolver的组件。如果有用容器中的,如果没有就为null

  • LocaleResolver:国际化解析器 zh_cn\en_us。来完成页面国际化功能
    从容器中获取LocaleResolver类型的组件,并且名为localeResolver。如果没有,加载 DispatcherServlet.properties文件中指定的。org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

  • ThemeResolver:主题解析器(用的比较少)

  • HandlerMapping: 处理器映射(解析了系统中所有Controller组件,缓存他们请求映射信息,。想要知道哪个请求由谁处理,在他里面找即可。 请求–controller–method)

    从容器中找 类型为HandlerMapping并且名字为handlerMapping的组件。没有就加载 DispatcherServlet.properties文件中指定默认的

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping(组件名字作为请求映射),\
  org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping(把@RequestMapping标注的路径作为请求的路径进行映射),\
   org.springframework.web.servlet.function.support.RouterFunctionMapping(webflux)

在这里插入图片描述

  • HandlerAdapter: handler(我们自己的controller)的适配器,未来决定目标方法如何执行的(反射进行请求处理的核心逻辑)。

    从容器中获取所有的 HandlerAdapter 组件。没有就加载默认值

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
   org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
  org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter(反射处理标注@RequestMapping注解的方法),\
   org.springframework.web.servlet.function.support.HandlerFunctionAdapter(webflux)

在这里插入图片描述

  • HandlerExceptionResolver:异常解析器
    从容器中获取所有的 HandlerExceptionResolver 组件。没有就加载默认值
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
   org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
   org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
  • RequestToViewNameTranslator:请求转为要跳转的视图名的转换器

    从容器中获取 RequestToViewNameTranslator 并且名为 viewNameTranslator;

#没有就加载默认的
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
  • ViewResolver:视图解析器。决定页面的视图跳转逻辑。

    • 容器中找到所有的 ViewResolver,
    • 如果没有SpringMVC会给我们自动配置一个 org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
  • FlashMapManager:闪存管理器。(重定向携带数据)【利用session进行闪存】

    • 从容器中获取类型为FlashMapManager 并且名字为 flashMapManager的组件
    • 如果没有,SpringMVC将加载一个默认的 org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

3.九大组件作用

1.HandlerMapping(保存全系统哪些请求,谁来处理的)

在这里插入图片描述

    @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            for (HandlerMapping mapping : this.handlerMappings) {
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }
        return null;
    }


    @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            Iterator var2 = this.handlerMappings.iterator();

            while(var2.hasNext()) {
                HandlerMapping mapping = (HandlerMapping)var2.next();
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }

        return null;
    }

HandlerMapping SpringBoot底层默认配置了。SpringBoot自己配置了

1-1RequestMappingHandlerMapping:最强大,自定义Controller+ @RequestMapping

利用InitializingBean机制,在创建完对象以后是分析全系统的所有组件,分析每个方法 @RequestMapping 注解信息,注册到请求映射里面

RequestMappingHandlerMapping 原理

1、什么时候被创建的?

  • 1、SpringBoot自动配置了SpringMVC功能,给容器中放了一个 RequestMappingHandlerMapping
  • 2、初始化所有非懒加载单实例Bean的时候会创建这个对象

2、创建这个Bean的时候 后置处理器 以及生命函数有没有对其进行功能增强?

1、后置处理器没干活

2、生命周期做事情、

  • Bean创建完对象,调用 InitializingBean.afterPropertiesSet】
  • 拿到容器中所有的组件名字
    • 获取当前名字的组件类型
    • 只要发现这个类上标注了 @RequestMapping 或者 @Controller注解,就认为是处理器
    • 利用反射扫描这个类的所有方法,把他们标注的@RequestMapping信息和method封装到HandlerMapping的mappingRegistry中。

3、怎么样的增强?

挨个方法扫描。请求映射信息缓存起来。以后所有的请求,上来就能找到当前请求使用哪个Handler进行处理

1-2、WelcomePageHandlerMapping: SpringBoot独家提供的 提供了 /** 路径下的所有资源在。

"classpath:/META-INF/resources/",
"classpath:/resources/", 
"classpath:/static/", 
"classpath:/public/" 的 index.html 下面找
以上是SpringBoot底层的静态资源路径
/** 
会有底层的 ParameterizableViewController 东西来处理请求

在这里插入图片描述

1-3、BeanNameUrlHandlerMapping

@Component("/abc")   //要想启用他,controller可以哦这么写
public class RequestController  implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ModelAndView modelAndView = new ModelAndView();
        response.getWriter().write("icoding 11111 ");
        return null;
    }
}

在这里插入图片描述

1-4、SimpleUrlHandlerMapping

SpringBoot自己用来适配静态资源的

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
   if (!this.resourceProperties.isAddMappings()) {
      logger.debug("Default resource handling disabled");
      return;
   }
   Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
   CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
   if (!registry.hasMappingForPattern("/webjars/**")) {
      customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
            .addResourceLocations("classpath:/META-INF/resources/webjars/")
            .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)
            .setUseLastModified(this.resourceProperties.getCache().isUseLastModified()));
   }
   String staticPathPattern = this.mvcProperties.getStaticPathPattern();
   if (!registry.hasMappingForPattern(staticPathPattern)) {
      customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
            .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
            .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)
            .setUseLastModified(this.resourceProperties.getCache().isUseLastModified()));
   }
}

在这里插入图片描述

	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping mapping : this.handlerMappings) {
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}
//所有的 HandlerMapping 挨个进行映射处理,如果能处理就返回对象,否则返回null,轮到下一个处理

1-5 自定义HandlerMapping

/api/v1/xxxxx;全部是v1的,全部去v1包下找映射

/api/v2/xxxxx;全部是v1的,全部去v2包下找映射

@Order(1)
@Component
public class BaiDuHandlerMapping /*extends AbstractUrlHandlerMapping*/ implements HandlerMapping {

    @Override
    public boolean usesPathPatterns() {
        return true;
    }

    @Override
    public HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

        String requestURI = request.getRequestURI();
        if(requestURI.startsWith("/baidu")){
            return  new HandlerExecutionChain(new Object());
        }
        return null;
    }
}

2、HandlerAdapter

HandlerMapping找到请求映射以后会给我们返回 HandlerExcutionChain

处理器的执行链

2-1、 HandlerExcutionChain
在这里插入图片描述

  • 如果我们方法标注了 @RequestMapping 注解会直接返回这个方法的详细信息。包装成 HandlerMethod
  • 如果我们写的简单处理器(不是用@RequestMapping做的)返回如下。原生的Handler和拦截 包装成 HandlerExcutionChain
    在这里插入图片描述

2-2、根据HandlerExcutionChain返回的handler需要找到适配器
底层4个适配器

  • RequestMappingHandlerAdapter:判断当前handler是不是 HandlerMethod,也就是由@RequestMapping解析到的
  • HandlerFunctionAdapter: 适配Webflux的
  • HttpRequestHandlerAdapter:看当前handler 是不是 HttpRequestHandler
  • SimpleControllerHandlerAdapter: 看当前handler 是不是 Controller

场景: 原来的SpringMVC不兼容直接写Servlet进行请求处理,自定义适配器+beanNameUrlHandlerMapping实现这个功能

/**
 * 执行实现了 Servlet 接口的类
 */
@Component
public class ServletHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean supports(Object handler) {
        return (handler instanceof Servlet);
    }

    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Servlet baiduHandler = (Servlet) handler;

        baiduHandler.service(request,response);

        return null;
    }

    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        return 0;
    }
}

3.参数解析流程

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. 返回值解析流程

在这里插入图片描述
在这里插入图片描述

返回值处理器的总接口:HandlerMethodReturnValueHandler

mavContainer:方法执行期间的一些关键数据,defaultModel一般保存方法运行期间给Model里面保存的数据
1、任何返回值的目标方法,处理结束后都会返回ModelAndView(以JSON返回mav为null,以页面返回才会有数据)

1、先确定目标方法的每一个参数的值(参数处理流程)

2、利用反射执行目标方法,并获取到目标方法执行后返回值 User@6557

3、利用返回值处理器处理返回值

	1、遍历所有的返回值处理器,看谁能处理这个返回值,返回这个处理器

	2、使用这个返回值处理器进行返回值的处理工作

		1、标记当前请求已经被处理 mavContainer.setRequestHandled(true);

		2、writeWithMessageConverters【json】,使用MessageConverter把数据写出去

		3、决定媒体类型(json、html、xml、image?)【内容协商】

			1、使用contentNegotiationManager(内容协商管理器)判断浏览器能接受的内容类型;默认使用HeaderContentNegotiationStrategy(基于请求头的内容协商)String[] headerValueArray = request.getHeaderValues("Accept");			

在这里插入图片描述

2、获取服务器能生产的内容类型。SpringBoot底层内置了很多的消息转换器HttpMessageConverter(代表了服务器的底层能力)。

在这里插入图片描述
3、最终消息转换器会把对象以json的方式写出去。ModelAndView会封装为null

1、返回对象,作为数据直接以json响应()

RequestResponseBodyMethodProcessor处理@ResonpseBody方式的返回值

总结:

1、所有的返回值处理器进行处理器,最终会使用RequestResponseBodyMethodProcessor来处理器

2、RequestResponseBodyMethodProcessor是利用底层的 HttpMessageConverter 将消息进行转换。

3、消息转换期间需要进行内容协商(多端适配)。

导入jacksonxml 包底层
在这里插入图片描述

2、页面渲染流程

返回的普通对象,String、Model、View、ModelAndView:就会跳转页面

String-》ViewNameMethodReturnValueHandler

1、ViewNameMethodReturnValueHandler处理字符串返回值,把字符串值设置到mavContainer中的viewName字段

2、mavContainer的model以及view的内容重新被封装成一个ModelAndView进行返回

3、如果方法返回void那么请求的路径就会被当成视图名(要跳转的页面地址)

4、进入视图解析流程

5、页面渲染流程

ViewResolver?View?

ViewResolver解析viewName得到View;View.render 才是真正页面逻辑的展示

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

拿到mv以及dispatchException开始进行处理

1、判断是否有异常。有异常处理异常。

2、没有异常进入页面渲染流程 render(mv, request, response);

1、根据方法的返回值viewName得到要去的页面的View对象

2、所有视图解析器看谁能知道当前viewName该去哪里

3、内容协商功能会把所有视图解析器都拿来组合起来,得到最终所有能解析的结果,最终根据内容协商原理选择一个最合适的View

4、得到View对象,调用View的render(渲染)

在这里插入图片描述
1、beanNameViewResolver: context.getBean(viewName, View.class);从容器中得到名为目标方法返回值的View组件

2、ThymeleafViewResolver: 直接用缓存中的,或者创建出视图;

返回值以redirect:开始;就会创建一个 RedirectView

返回值以forward:开始;就会创建一个 InternalResourceView

不以上面的开始就loadView;

	1、看容器中有没有 viewName的View对象

	2、没有1就创建一个 ThymeleafView对象;名字就叫viewName。并且放在容器中(利用了缓存)。

6、异常解析流程(HandlerExceptionResolver)

在这里插入图片描述

if (exception != null) {
			if (exception instanceof ModelAndViewDefiningException) {
				logger.debug("ModelAndViewDefiningException encountered", exception);
				mv = ((ModelAndViewDefiningException) exception).getModelAndView();
			}
			else {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
                //处理完异常继续返回modelAndView
				mv = processHandlerException(request, response, handler, exception);
				errorView = (mv != null);
			}
		}
		
		//渲染modelAndView
		render(mv, request, response);
1、SpringBoot中对异常处理自动配置

分析 ErrorMvcAutoConfiguration;

  • 1、绑定了两个配置类 ServerProperties.class, WebMvcProperties.class ,异常配置可以参照
  • 2、给容器中放了如下组件
    • DefaultErrorAttributes: ErrorAttributes, HandlerExceptionResolver(处理器异常解析器)
      • HandlerExceptionResolver最终解析异常返回ModelAndView对象。最终这个mav对象会被渲染
      • 第一次目标方法出现异常,先把异常信息存起来,第二次/error进来把上次请求发送的所有错误信息转为map
        在这里插入图片描述
  • BasicErrorController:一个处理器,处理 /error请求。基于内容协商可以适配。如果是html就返回ModelAndView,如果是json就返回 ResponseEntity<Map<String, Object>>
  • ErrorPageCustomizer: 错误页的定制化器,系统发生错误,自动发送 /error 请求将错误传递下去
  • DefaultErrorViewResolver: ErrorViewResolver,默认的错误视图解析器
  • View:名字叫error的错误视图。
  • BeanNameViewResolver:beanName的视图解析器,按照bean的名字在容器中找View组件
2、ExceptionHandlerExceptionResolver

1、使用@ExceptionHandler标准的异常处理方法能写以下参数
在这里插入图片描述2、使用@ExceptionHandler标准的异常处理方法能写以下返回
在这里插入图片描述
3、执行使用 @ExceptionHandler 标注的异常处理方法。共享适配器执行目标方法的流程

  • 使用参数解析器确定参数值,
  • 目标方法执行
  • 使用返回值处理器处理返回值
3、ResponseStatusExceptionResolver

处理自定义异常标注 @ResponseStatus 注解。

如果自定异常标注了注解

  • 1、如果 @ResponseStatus 没有指定reason,就会 response.sendError(statusCode);
  • 2、如果 @ResponseStatus 指定reason,reason可国际化解析,然后 response.sendError(statusCode, resolvedReason);
    response.sendError(statusCode); 默认是

在这里插入图片描述实际上是:
在这里插入图片描述

4、DefaultHandlerExceptionResolver

底层的异常会触发这个异常解析器。效果是:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值