Spring Framework源码(十一):SpringMVC之URL匹配
来源:互联网 发布:工业管道绘图软件 编辑:程序博客网 时间:2024/05/23 00:35
要了解SpringMVC中数据是怎么绑定到Controller的参数上的之前我们需要知道SpringMVC是从哪里开始解析数据的。首先我们回顾下DispatcherServlet中的doDispatch中的如下代码:
mappedHandler = getHandler(processedRequest);
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
首先SpringMVC要充HandlerMapping中获取对应的HandlerExecutionChain类型的handler,那么这是怎么获取的呢?我们以SpringMVC使用的默认HandlerMapping即org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping为例进行讲解。
public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {@Overrideprotected String[] determineUrlsForHandler(String beanName) {List<String> urls = new ArrayList<String>();if (beanName.startsWith("/")) {urls.add(beanName);}String[] aliases = getApplicationContext().getAliases(beanName);for (String alias : aliases) {if (alias.startsWith("/")) {urls.add(alias);}}return StringUtils.toStringArray(urls);}}
BeanNameUrlHandlerMapping仅仅实现了一个determineUrlsForHandler方法。在此之前它在doDispatch方法中被调用的getHandler方法是在父类AbstractHandlerMapping中实现的。
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {//获取内部HandlerObject handler = getHandlerInternal(request);//内部Handler不存在的情况下获取默认handlerif (handler == null) {handler = getDefaultHandler();}if (handler == null) {return null;}//如果返回的是一个bean name则转化成一个beanif (handler instanceof String) {String handlerName = (String) handler;handler = getApplicationContext().getBean(handlerName);}//根据获取的handler封装成一个执行链,这个执行链实际是一个由N个interceptor和一个controller组成的链式结构return getHandlerExecutionChain(handler, request);}
子类AbstractUrlHandlerMapping中的getHandlerInternal(HttpServletRequest)方法。
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {//没配置使用全路径的情况下获取相对路径如http://www.xxx.com/path/aaa/bbb的相对路径是/path/aaa/bbbString lookupPath = getUrlPathHelper().getLookupPathForRequest(request);//根据request的url获取handler,这里的handler就是一个controller。Spring的在创建ApplicationContext时会//根据Controller的注解或bean定义以<url,controller>的键值对的形式将所有controller的路径映射信息保存到一个map中//lookupHandler会利用url从map中get到这个controllerObject handler = lookupHandler(lookupPath, request);if (handler == null) {Object rawHandler = null;//如果访问web应用首页映射到根目录处理器if ("/".equals(lookupPath)) {rawHandler = getRootHandler();}//如果没有controller则使用默认controllerif (rawHandler == null) {rawHandler = getDefaultHandler();}if (rawHandler != null) {//如果是bean name转化成controllerif (rawHandler instanceof String) {String handlerName = (String) rawHandler;rawHandler = getApplicationContext().getBean(handlerName);}validateHandler(rawHandler, request);//增加一个过滤器,用于暴露URI_TEMPLATE_VARIABLES_ATTRIBUTE属性handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);}}//省略代码若干...return handler;}
看完以上代码我们大致了解了在执行完getHandler后我们得到了一个由N个interceptor和一个controller构成的HandlerExecutionChain,接着我们要找到对应的HandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {for (HandlerAdapter ha : this.handlerAdapters) {if (logger.isTraceEnabled()) {logger.trace("Testing handler adapter [" + ha + "]");}//如果该种Adapter支持Handler则返回Adapterif (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");}
它会挨个调用默认的Adapter的support方法判断是否支持该种handler如果支持则返回。返回Adapter后会直接调用handle方法获取ModelAndView。由于通常我们是使用注解来标示控制器的,这里我们以org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter为例来看看Adapter是怎么形式其责任的。
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception { //获取controller的classClass<?> clazz = ClassUtils.getUserClass(handler); //获取注解信息Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz);if (annotatedWithSessionAttributes == null) {annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null);this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes);}if (annotatedWithSessionAttributes) {// Always prevent caching in case of session attribute management.checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);// Prepare cached set of session attributes names.}else {// Uses configured default cacheSeconds setting.checkAndPrepare(request, response, true);}// Execute invokeHandlerMethod in synchronized block if required.if (this.synchronizeOnSession) {HttpSession session = request.getSession(false);if (session != null) {Object mutex = WebUtils.getSessionMutex(session);synchronized (mutex) {return invokeHandlerMethod(request, response, handler);}}} //调用注解下面的方法return invokeHandlerMethod(request, response, handler);}protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception { //获取方法处理器ServletHandlerMethodResolver methodResolver = getMethodResolver(handler); //获取controller相应的方法Method handlerMethod = methodResolver.resolveHandlerMethod(request);ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver); //包装request和responseServletWebRequest webRequest = new ServletWebRequest(request, response);ExtendedModelMap implicitModel = new BindingAwareModelMap(); //调用方法Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);//返回ModelAndView对象 ModelAndView mav =methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);return mav;}
这样用户传入的url就正确地匹配到了具体的方法中了。
- Spring Framework源码(十一):SpringMVC之URL匹配
- Spring Framework源码(九):SpringMVC之从DispatcherServlet说起
- Spring Framework源码(十):SpringMVC之文件上传
- Spring Framework源码(八):SpringMVC概览
- Spring Framework源码(十二):SpringMVC之数据绑定、验证、转换
- Spring Framework源码(十三):SpringMVC之从ModelMap到页面渲染
- springMVC源码分析--AbstractHandlerMethodMapping注册url和HandlerMethod对应关系(十一)
- Spring Framework源码(一):spring beans之BeanFactory
- Spring Framework源码(六):Spring AOP之解析标签
- Spring Framework源码(七):Spring AOP之
- url不匹配和springmvc返回jsp源码
- spring framework源码解析之序言
- SSM框架整合(IntellIj IDEA+Maven+Spring+SpringMVC+MyBatis)之Spring Framework
- robot-framework 源码阅读 之 suite name 搜索匹配
- Spring源码学习--WebApplicationContext(十一)
- Spring Framework源码(二):spring beans之ApplicationContext
- SpringMVC源码总结(十一)mvc:interceptors拦截器介绍
- SpringMVC源码总结(十一)mvc:interceptors拦截器介绍
- 速学 latex 数学公式
- bzoj1072: [SCOI2007]排列perm 压状dp
- Chapter10-IO 重叠IO 完成例程
- Gson 使用fromGson(String,.class)无法转成其他对象
- JSON和JS对象之间的互转
- Spring Framework源码(十一):SpringMVC之URL匹配
- 天祥 TX2440 UBOOT移植(2. 支持NANDFLASH)
- matlab libsvm 交叉验证
- 2014年WEB高手都在做什么
- 交换机网络嗅探方法之用ARP欺骗辅助嗅探
- ptrace 捕捉系统调用 x64 version
- Ubuntu不能用apt-get更新,软件源更新(非LTS长久支持版)
- 通过HttpServletRequestWrapper(装饰模式的应用)增强HttpServletRequest的功能
- getPositionForSection与getSectionForPosition