一次请求的源码分析过程
来源:互联网 发布:化工项目网络计划绘制 编辑:程序博客网 时间:2024/06/06 08:35
一次请求的源码分析过程
<!-- **********************下次处理:为什么我们请求后,解析处理返回ModelAndView,那为什么我们有时候在请求controller后返回一个json数据,有的是一个页面, 这块springmvc是怎么处理的,是否支持一些别的扩展, --> <!-- 最后 **** 拿到中置拦截器处理得到的ModelAndView 处理程序选择和处理程序调用的结果 模型和视图,或者是一个可以解析为模型和视图的异常。 DispatcherServlet.processDispatchResult(); //处理数据请求响应处理结束,http连接断开,释放资源 --> <!-- 过后就是中置拦截器 interceptor.postHandle 视图解析器,从ModelAndView中解析 ViewResolve 后置拦截器(关闭连接,释放资源) interceptor.afterCompleton --> <!-- HandlerAdapter.handle() 适配器去调用具体的controller处理器 // 实际调用处理程序。 ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); RequestMappingHandlerAdapter.invokeHandleMethod() //去调用这个实际的HandleMethod,就是方法调用 //注定参数解析多种多样 InvocableHandlerMethod.getMethodArgumentValues() //获取这些method方法参数的值,并解析处理 //拿到所有参数 MethodParameter[] parameters = getMethodParameters(); //请求通过requst对象中传入入参值,封装成数组,拿到之前的method对象,通过method.invoke(bean, args); //arg数组来调用具体的方法 //可以扩展,不同的参数类型对应不同的处理类*** 重要 // 参数解析处理逻辑 if (this.argumentResolvers.supportsParameter(parameter)) { try { args[i] = this.argumentResolvers.resolveArgument( parameter, mavContainer, request, this.dataBinderFactory); continue; } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(getArgumentResolutionErrorMessage("Error resolving argument", i), ex); } throw ex; } } HandlerMethodArgumentResolver //扩展解析参数处理类的最顶层接口 //argumentResolvers 这个是什么时候初始化的,是在启动的时候初始化的,也是通过initBean来加载初始化注册的 //解答:在这个类中通过InitializingBean来初始化的 public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean { getDefaultArgumentResolvers //这个方法完成初始化 HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter); if (result == null) { for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) { if (logger.isTraceEnabled()) { logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" + parameter.getGenericParameterType() + "]"); } if (methodArgumentResolver.supportsParameter(parameter)) { result = methodArgumentResolver; this.argumentResolverCache.put(parameter, result); break; } } } //通过这个methodArgumentResolver.supportsParameter(parameter) 可以查看到默认支持的参数解析有哪些 if (methodArgumentResolver.supportsParameter(parameter)) { result = methodArgumentResolver; this.argumentResolverCache.put(parameter, result); break; } //获取request中的参数,并解析处理参数,处理完返回请求参数去调用具体的method方法,通过invoke Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); Object returnValue = invoke(args); private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) { return null; } ModelMap model = mavContainer.getModel(); //ModelAndViewContainer的封装 ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } return mav; //返回结果集和页面 } ModelAndView //再给后置拦截器去显示解析返回给浏览器 --> <!-- 前置拦截器,拦截请求,true或false 当mappedHandler.applyPreHandle(processedRequest, response)返回false,就不往下执行了 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } --> <!-- handlerAdapter - 负责去调用具体的controller里面的方法的,contrller中有多个方法,handlerAdapter去决定调用哪个方法 适配参数,如何二个参数的方法,三个参数的方法,参数的格式和类型肯定不一样,所有handlerAdapter可以解析我们的处理器 方法的参数,这里使用的是一个策略模式 和返回去参数的解析,返回参数的解析也是通过策略模式去解析返回参数,比如controller 中不同方法的返回参数类型,如string void map 等 //为当前请求确定处理程序适配器。 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); //这里会根据具体的HandlerMethod去找到一个具体的HandlerAdapter适配器,spring在启动的时候就会默认注册4个HandlerAdapter if (ha.supports(handler)) { //策略模式的使用,方便扩展,使用不同的handler可以循环去找到对应的HandlerAdapter return ha; } interceptorIndex //由于拦截器是一个链式结构 //TODO 扩展拦截器的认识 //调用每个拦截器的前置拦截器 if (getInterceptors() != null) { for (int i = 0; i < getInterceptors().length; i++) { HandlerInterceptor interceptor = getInterceptors()[i]; if (!interceptor.preHandle(request, response, this.handler)) { //1.首先先去调用这个拦截器的preHandle()方法 //当这个拦截器是怎么时候注册进来的,自定义要如何写??? } this.interceptorIndex = i; //给所有的拦截器编号 0, 1 , 2 } } //调用每个拦截器的中置拦截器 for (int i = getInterceptors().length - 1; i >= 0; i ————) { HandlerInterceptor interceptor = getInterceptors()[i]; interceptor.postHandle(request, response, this.handler, mv); // 2.调用中置拦截器 // 调用顺序 3, 2, 1 //调用后置拦截器 for (int i = this.interceptorIndex; i >= 0; i————) { HandlerInterceptor interceptor = getInterceptors()[i]; try { interceptor.afterCompletion(request, response, this.handler, ex); //3. 调用后置拦截器 //调用顺序 3,2, 1 } catch (Throwable ex2) { logger.error("HandlerInterceptor.afterCompletion threw exception", ex2); } } --> <!-- 如: /session/login 请求路径 /session 能确定一个controller /login 能确定一个method DispatcherServlet 本身就是一个servlet,所以请求过来首先会访问它父类FrameworkServlet.service()方法 > DispatcherServlet.doDispatch() mappedHandler = getHandler(processedRequest); //获取当前请求的处理器,并包装成HandlerExecutionChain //遍历启动时注册的handlerMappings 并为每一个handlerMappings包装成一个处理类 for (HandlerMapping hm : this.handlerMappings) { handlerExecutionChain handler = hm.getHandler(request);} //查找给定请求的处理程序方法。 AbstractHandlerMethodMapping.getHandlerInternal() //拿到请求url /session/login String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); //根据url来拿到HandlerMethod对象 HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); //urlMap 是一个url和控制器中的方法 url:控制器方法类解析数值 map 就是url和HandlerMethod的映射,那是什么时候加上的注册,那肯定是在启动的时候就注册到map中的 List<T> directPathMatches = this.urlMap.get(lookupPath); //handlerMethod中建立一个url和controller中login()方法定映射,那映射是什么时候建立的了,还是在容器初始化是就建立了 Map<T, HandlerMethod> handlerMehod = this.handlerMethods(); //this.handlerMethods() 是这个类中的一个map,这个抽象类继承了InitializingBean,重点落在这个类中了 //所以会在实例化该类调用afterPropertiesSet().initHandlerMethods();这个方法来完成handlerMehod的初始化 AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean //循环遍历在初始化时注册到容器的beans数据集合并遍历去判断存在@Controller和@RequestMapping的bean String[] beanNames //先通过beanName来获取容器中的Class<?>反射对象,并用Class对象来匹配是否存在如下二个注解的类 @Override protected boolean isHandler(Class<?> beanType) { return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) || (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null)); } //判断过后,detectHandlerMethods(beanName);这个方法只会走带有注解的类 //相当于过滤,因为只有控制器才有url和方法的映射 for (String beanName : beanNames) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(beanName))){ detectHandlerMethods(beanName); } } final Map<Method, T> mappings = new IdentityHashMap<Method, T>(); Method:CommitteeActivityController.AddInfo(param) T: { [/committee/activity//activity], methods=[GET], params=[], headers=[], consumes=[], produces=[], custom=[] } //先拿到对应类的Class对象,并获取该类下的所有方法 //new MethodFilter() 采用匿名类的方式来过滤method Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() { @Override public boolean matches(Method method) { T mapping = getMappingForMethod(method, userType); if (mapping != null) { mappings.put(method, mapping); return true; } else { return false; } } }); //并注册到this.handlerMethods.put(mapping, newHandlerMethod); map中 for (Method method : methods) { registerHandlerMethod(handler, method, mappings.get(method)); } //将HandlerMethod封装到handlerExecutionChain中 return getHandlerExecutionChain(handler, request); //TODO 10.10 propress doWith() 54:13 //迭代继续寻找父类中的方法 ReflectionUtils.doWithMethods() if (clazz.getSuperclass() != null) { doWithMethods(clazz.getSuperclass(), mc, mf); } //迭代继续寻找接口的方法 else if (clazz.isInterface()) { for (Class<?> superIfc : clazz.getInterfaces()) { doWithMethods(superIfc, mc, mf); } } //拿到带有@RequestMapping的方法,获取注解上的属性 AbstractHandlerMethodMapping.getMappingForMethod() RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class); //拿到注解上的属性 String[] params() default {}; //包装method的参数信息 RequestMappingInfo info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info); //封装成实体 return new RequestMappingInfo( new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(), this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions), new RequestMethodsRequestCondition(annotation.method()), new ParamsRequestCondition(annotation.params()), new HeadersRequestCondition(annotation.headers()), new ConsumesRequestCondition(annotation.consumes(), annotation.headers()), new ProducesRequestCondition(annotation.produces(), annotation.headers(), this.contentNegotiationManager), customCondition); //先循环每一个bean,扫描到有@Controller和@RequestMapping注解的类,并扫描对应类中的所有方法(包括父类和接口的) //注册Map<Method, T>的对应关系,然后遍历这些newHandlerMethod把它和mapping T 建立map关系于handlerMethods中 this.handlerMethods.put(mapping, newHandlerMethod); //请求过来就直接去注册的map中去找对应的url就能匹配到对应的类和类的信息 //回归正常的请求流程(如上是启动的自动initBean接口时自动注册到map的初始化流程)4 //根据请求的url去handlerMethods去获取对应的HandlerMethod对象 HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); //将获取到的HandlerMethod又封装到Match对象中 Object handler = getHandlerInternal(request); //拿到对应请求url的HandlerMethod对象 //又将HandlerMethod 封装到HandlerExecutionChain return getHandlerExecutionChain(handler, request); //将所有的拦截器都添加到Handler处理器中 chain.addInterceptors(getAdaptedInterceptors()); HandlerInterceptor//类中存在前,中,后置拦截器 // HandlerExecutionChain中有如下二个属性 private final Object handler; //HandlerMethod private HandlerInterceptor[] interceptors; //拦截器 --> <!-- 定义HandlerMapping(请求的url:handlerMethod【controller中的方法】)的对应关系 这个关系都是第一次都是第一次请求过来以后就建立映射关系,并放到内存map中去,方便下次直接查找使用, 1.先判断是否支持HandlerMapping 2.从自定义实现HandlerMapping中去找子类 3.从注册的bean中找id等于handlerMapping的HandlerMapping 4.用默认的HandlerMapping来,是 spring自己配置,有二个默认配置 <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"></bean> -->
阅读全文
0 0
- 一次请求的源码分析过程
- Tomcat源码分析--一次HTTP请求过程
- SpringMVC一次请求过程源码分析
- struts2的请求处理过程源码分析
- struts2的请求处理过程源码分析
- struts2的请求处理过程源码分析
- 分析一次springmvc的执行过程,springmvc如何处理请求
- Tomcat源码分析(二)------ 一次完整请求的里里外外
- Tomcat源码分析(二)------ 一次完整请求的里里外外
- Tomcat源码分析(二)------ 一次完整请求的里里外外
- Tomcat源码分析(二)------ 一次完整请求的里里外外
- Tomcat源码分析(二)------ 一次完整请求的里里外外 .
- Tomcat源码分析------ 一次完整请求的里里外外
- Tomcat源码分析(二)------ 一次完整请求的里里外外
- Tomcat源码分析-- 一次完整请求的里里外外
- Tomcat源码分析(二)------ 一次完整请求的里里外外
- Tomcat源码分析(二)------ 一次完整请求的里里外外
- Tomcat源码分析(二)------ 一次完整请求的里里外外
- Linux下tomcat实时日志查看
- Spring基础-4-AOP注解
- CSAPP阅读笔记
- HDU
- POJ 1679 The Unique MST 次小生成树
- 一次请求的源码分析过程
- bootstrap table使用总结
- cordova构建app偶遇mergeDebugResources失败的问题
- HDU-5938:Four Operations(DP)
- 【c++基础】笔记(二)
- 面试记录第十九节——(MVC)
- Java水仙花数
- 使用Git管理代码
- java输出1~100之间的全部素数