14.请求映射的原理
当所有的请求来了时,会先进入DispatcherServlet类中的doDispatch进行处理
如请求路径是:http://localhost:8080/hello?id=12时
DispatcherServlet类的代码片段如下:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
....
//重点1.根据请求请求路径:hello,去查找是哪个类进行处理该请求
mappedHandler = getHandler(processedRequest);
1.1该方法中的细节:遍历handlerMappings,判断哪个程序处理链可以处理该请求
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
//重点2.handlerMappings有五项选择:
//1.RequestMappingHandlerMapping
//2.WelcomePageHandlerMapping
//3.beanNameHandlerMapping
//4.routerFunctionMapping
//5.SimpleUrlHandlerMapping
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
...
//重点3.获取处理程序的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
2.1该方法中的细节:遍历handlerAdapters,获取执行该程序的适配器
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
//重点4.handlerAdapters有四项选择,和handlerMappings对应
//1.RequestMappingHandlerAdapter
//2.HandlerFunctionAdapter
//3.HttpRequestHandlerAdapter
//4.SimpleControllerHandlerAdapter
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
....
重点5.执行控制方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
重点6.handle方法细节:一层套一层最终会调用到:
mav = invokeHandlerMethod(request, response, handlerMethod);
重点7invokeHandlerMethod方法细节
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
...
//重点8.设置参数解析器,argumentResolvers 有27项选择,细节如下截图,用来解析各种类型的请求参数
//springmvc目标方法能写多少种参数类型。取决于参数解析器。
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
//重点9.设置返回值处理器,控制方法helloControler可以返回多少中类型,去接于返回值处理器支持多少种,返回值处理器详情见截图
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
...
//重点10.执行目标方法
invocableMethod.invokeAndHandle(webRequest, mavContainer);
//重点11.该方法的细节如下:
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,Object... providedArgs){
//重点12.执行目标方法的地方
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
//重点13.该方法的详细信息如下:
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//重点14.确定目标方法参数值
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
//重点15.反射执行目标方法
return doInvoke(args);
}
}
}
}
重点15:如何确认目标方法参数值的
获取目标参数值的方法详情,是重点14方法的详情分
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {
//重点16.获取目标方法的参数列表,获取的是参数列表的详细信息,如参数类型,所标注的注解等,但此时还没有拿到参数值!
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
....
重点16.检查哪种参数解析器可以解析当前参数(supportsParameter方法里会遍历27种参数解析器,确定哪种参数解析器可以解析当前参数)
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
//重点17:找到适应的参数解析器,解析当前参数
try {
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
....
return args;
}
参数解析器细节,用来解析各种带标签的请求参数
参数解析器实现的接口如下:
返回值处理器