SpringMVC源码流程(一)

目录

一、先来看SpringMVC的初始化(前奏)

1、SpringMVC的九大组件:

2、对于九大组件,前端控制器DispatcherServlet会进行初始化

        二、SpringMVC执行流程

1)找到源码入口

2)进入到DispatcherServlet的doDispatch()

3)各方法的具体实现细节

①getHandler()获取处理器

②getHandlerAdapter()获取适配器

③执行目标方法的细节;


一、先来看SpringMVC的初始化(前奏)

1、SpringMVC的九大组件:

(这是mvc核心的部分,后面的mvc的流程以及其他功能都需要依靠这九大组件)

multipartResolver:文件上传解析器

localeResolver:区域信息解析器,和国际化有关

themeResolver:主题解析器

handlerMappings:handler的映射器

handlerAdapters:handler的适配器

handlerExceptionResolvers:异常解析功能

viewNameTranslator:请求到视图名的转换器

flashMapManager:SpringMVC中允许重定向携带数据的功能

viewResolvers:视图解析器

2、对于九大组件,前端控制器DispatcherServlet会进行初始化

DispatcherServlet中:onRefresh()->initStrategies()
 
protected void initStrategies(ApplicationContext context) {
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        initHandlerMappings(context);
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        initRequestToViewNameTranslator(context);
        initViewResolvers(context);
        initFlashMapManager(context);
    }

例如:初始化HandlerMapping(后面需要用到,先了解知道一下就可以哦)

private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;
        if (this.detectAllHandlerMappings) {
            // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
            Map<String, HandlerMapping> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
                // We keep HandlerMappings in sorted order.
                OrderComparator.sort(this.handlerMappings);
            }
        }
        else {
            try {
                HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default HandlerMapping later.
            }
        }

        // Ensure we have at least one HandlerMapping, by registering
        // a default HandlerMapping if no other mappings are found.
        if (this.handlerMappings == null) {
            this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
            if (logger.isDebugEnabled()) {
                logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
            }
        }
    }

***********关键点来喽~~~

组件的初始化: 有些组件初始化在容器中是使用类型找的,有些组件是使用id找的;
去容器中找这个组件,如果没有找到就用默认的配置;
注意点:如果后面需要自己实现的组件需要在ioc容器中注册,而注册的时候有些组件就需要专门指定的id才可以去注入成功(否则注入不上的)

二、SpringMVC执行流程

1)找到源码入口

  1. 当客户端发送请求时,会被tomcat拦截,进入到doGet或者doPost的方法中去
  2. 根据继承关系,FrameworkServlet会将基类的HttpServlet的doGet和doPost重写,并且调用doService()
  3. 前端控制器DispatcherServlet继承FrameworkServlet后重写了doService()方法,经过调用,进入到doDispatch()经过这么一些曲折的寻找,最后终于可以根据源码来探究mvc的流程了

2)进入到DispatcherServlet的doDispatch()

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        try {
            ModelAndView mv = null;
            Exception dispatchException = null;
            try {
                
                 //1、检查是否文件上传请求
                processedRequest = checkMultipart(request);
                multipartRequestParsed = processedRequest != request;
                
                // Determine handler for the current request.
                 //2、根据当前的请求地址找到那个类能来处理;
                mappedHandler = getHandler(processedRequest);
 
 
                 //3、如果没有找到哪个处理器(控制器)能处理这个请求就404,或者抛异常
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
 
 
                // Determine handler adapter for the current request.
                 //4、拿到能执行这个类的所有方法的适配器;(反射工AnnotationMethodHandlerAdapter)
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
                
                // Process last-modified header, if supported by the handler.
                
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        String requestUri = urlPathHelper.getRequestUri(request);
                        logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
                try {
                    
                    // Actually invoke the handler.处理(控制)器的方法被调用
                    //控制器(Controller),处理器(Handler)
                     //5、适配器来执行目标方法;
                     //将目标方法执行完成后的返回值作为视图名,设置保存到ModelAndView中
                    //目标方法无论怎么写,最终适配器执行完成以后都会将执行后的信息封装成ModelAndView
                    
                    mv = ha.handle(processedRequest,response,mappedHandler.getHandler());
                } finally {
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
                }
                applyDefaultViewName(request, mv);//如果没有视图名设置一个默认的视图名;
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            } catch (Exception ex) {
                dispatchException = ex;
            }
            
             //转发到目标页面;
            //6、根据方法最终执行完成后封装的ModelAndView;
            //转发到对应页面,而且ModelAndView中的数据可以从请求域中获取
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        } catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        } catch (Error err) {
            triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                
                // Instead of postHandle and afterCompletion
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                return;
            }
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }

******由此,可以总结为如下几个大概方面

1.用户发出请求,DispatcherServlet接收请求并拦截请求。
2.调用doDispatch()方法进行处理:
        1. getHandler():根据当前请求地址中找到能处理这个请求的目标处理器类(处理器);
            1.根据当前请求在HandlerMapping中找到这个请求的映射信息,获取到目标处理器类
            2. mappedHandler = getHandler(processedRequest);
        2. getHandlerAdapter():根据当前处理器类找到能执行这个处理器方法的适配器;
            1.根据当前处理器类,找到当前类的HandlerAdapter (适配器)
            2. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler();
        3.使用刚才获取到的适配器(AnnotationMethodHandlerAdapter)执行目标方法;
             mv = ha.handle(processedRequest,response,mappedHandler.getHandler());
        4.目标方法执行后,会返回-个ModerAndView对象
             mv = ha.handle(processedRequest,response,mappedHandler.getHandler();
        5.根据ModerAndView的信息转发到具体页面,并可以在请求域中取出ModerAndView中的模型数据
           processDispatchResult(processedRequest, response, mappedHandler, mv,dispatchException);

根据前面的doDispatch(),有两个组件我们需要使用到,那么再来强调一下这两个组件是干嘛的呢?

HandlerMapping为处理器映射器,保存了每一个处理器能处理哪些请求的映射信息,handlerMap

HandlerAdapter为处理器适配器,能解析注解方法的适配器,其按照特定的规则去执行Handler
 

3)各方法的具体实现细节

①getHandler()获取处理器

     **怎么根据当前请求就能找到哪个类能来处理?**
  • getHandler()会返回目标处理器类的执行链
  • HandlerMapping:处理器映射:他里面保存了每一个处理器能处理哪些请求的映射信息
  • handlerMap:ioc容器启动创建Controller对象的时候扫描每个处理器都能处理什么请求,保存在HandlerMapping的handlerMap属性中;下一次请求过来,就来看哪个HandlerMapping中有这个请求映射信息就行
循环遍历拿到能处理url的类
 
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        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;
    }

注意点:遍历循环的this.handlerMappings里面在初始化前端控制器的时候就有东西了,有指定的处理器能处理就拿到该处理器,并直接返回。

②getHandlerAdapter()获取适配器

拿到适配器,通过适配器来调用目标方法

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        for (HandlerAdapter ha : this.handlerAdapters) {
            if (logger.isTraceEnabled()) {
                logger.trace("Testing handler adapter [" + ha + "]");
            }
            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");
    }
RequestMappingHandlerAdapter适配器:
  • 能解析注解方法的适配器;

  • 处理器类中只要有标了注解的这些方法就能用;

③执行目标方法的细节;

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
 
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
          //拿到方法的解析器
        ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
           //方法解析器根据当前请求地址找到真正的目标方法
        Method handlerMethod = methodResolver.resolveHandlerMethod(request);
           //创建一个方法执行器;
        ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
           //包装原生的request, response,
        ServletWebRequest webRequest = new ServletWebRequest(request, response);
           //创建了一个,隐含模型
        ExtendedModelMap implicitModel = new BindingAwareModelMap() ;//**重点
 
 
         //真正执行目标方法;目标方法利用反射执行期间确定参数值,提前执行modelattribute等所有的操作都在这个方法中;
        Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
      
        ModelAndView mav = methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
    
        methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
    
        return mav;
    }

接下来深入到执行目标方法,来看看他们是如何执行的吧

Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);

publicfinal Object invokeHandlerMethod (Method handlerMethod, Object handler,
            NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {
        Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);
        try {
            boolean debug = logger.isDebugEnabled();
            for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
                Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);
                if (attrValue != null) {
                    implicitModel.addAttribute(attrName, attrValue);
                }
            }
               
          //找到所有@ModelAttribute注解标注的方法;
            for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
                Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
                //先确定modelattribute方法执行时要使用的每一个参数的值;
               Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);
                if (debug) {
                    logger.debug("Invoking model attribute method: " + attributeMethodToInvoke);
                }
                String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value();
                
                if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
                    continue;
                }
                
                ReflectionUtils.makeAccessible(attributeMethodToInvoke);
               
               //提前运行ModelAttribute
                Object attrValue = attributeMethodToInvoke.invoke(handler, args);
                if ("".equals(attrName)) {
                    Class<?> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
                    attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);
                }
              
                //把提前运行的ModelAttribute方法的返回值也放在隐含模型中
                if (!implicitModel.containsAttribute(attrName)) {
                    implicitModel.addAttribute(attrName, attrValue);
                }
            }
 
 
               //再次解析目标方法参数是哪些值
             Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);
            if (debug) {
                logger.debug("Invoking request handler method: " + handlerMethodToInvoke);
            }
            ReflectionUtils.makeAccessible(handlerMethodToInvoke);
 
 
            
            //执行目标方法
            return handlerMethodToInvoke.invoke(handler, args);
        }
        catch (IllegalStateException ex) {
            // Internal assertion failed (e.g. invalid signature):
            // throw exception with full handler method context...
            throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex);
        }
        catch (InvocationTargetException ex) {
            // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception...
            ReflectionUtils.rethrowException(ex.getTargetException());
            return null;
        }
    }
对于前期的框架,相信大家应该有了一个框图,知道大概的流程模样。
接下来,对于到底具体如何执行目标方法的呢,请看SpringMVC流程(二)
 
 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值