详解SpringMVC从基础到源码

网友投稿 289 2022-11-21


详解SpringMVC从基础到源码

认识SpringMVC

SpringMVC 框架是以请求为驱动,围绕 Servlet 设计,将请求发给控制器,然后通过模型对象,分派器来展示请求结果视图。其中核心类是 DispatcherServlet,它是一个 Servlet,顶层是实现的Servlet接口。

SpringMVC 处理请求过程

客户端发起请求,会首先经过前端控制器 DispatcherServlet 进行转发,转发到 Handler Mapping

DispatcherServlet 从 Handler Mapping 查找处理请求的 Controller,Handler Mapping 作用就是完成 URL 到 Controller 的映射

Controller 处理请求并返回 ModelAndView 对象,ModelAndView 是封装结果视图的组件

再将视图结果返回给客户端

Servlet 与 SpringMVC

SpringMVC 是在 Servlet 的基础上进行了扩展,看看他们的继承关系是什么样的。

Servlet 继承关系

SpringMVC 继承关系

Servlet 与 SpringMVC 对比

Servlet 需要每个请求都在 web.xml 文件中配置一个 sevlet 节点

SpringMVC 的 DispatcherServlet 会拦截所有请求,让 Controller 去处理

Structs2 与 Spring MVC

相同点

都是基于MVC模型的

不同点

Structs2 是基于类的,一个 request 创建一个 action,一个action 对应一个 request ;Servlet 是基于方法的,也就是一个 request 对应一个方法

Structs2 入口是 Filter;SpringMVC 入口是 Servlet

SpringMVC 的开发速度和性能优于 Structs2 ,流程更易理解

SpringMVC 和 Spring 是无缝的,可以认为 SpringMVC 是100% 零配置

SpringMVC源码分析

1、ApplicationContext 初始化时建立所有的URL和Controller 的对应关系

/**

* 建立当前ApplicationContext中的所有controller和url的对应关系

*/

protected void detectHandlers() throws BeansException {

//日志级别是否是 Debug

if (logger.isDebugEnabled()) {

//应用上下文就是工程的访问路径

logger.debug("Looking for URL mappings in application context: " + getApplicationContext());

}

     // 获取ApplicationContext容器中所有bean的Name---Controller

String[] beanNames = (this.detectHandlersInAncestorContexts ?

BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :

getApplicationContext().getBeanNamesForType(Object.class));

// 遍历beanNames,并找到这些bean对应的url

for (String beanName : beanNames) {

       // 获取Controller上的所有url(类上的url+方法上的url)

String[] urls = determineUrlsForHandler(beanName);

if (!ObjectUtils.isEmpty(urls)) {

// 保存urls和beanName的对应关系,put it to Map,该方法在父类AbstractUrlHandlerMapping中实现

registerHandler(urls, beanName);

}

else {

if (logger.isDebugEnabled()) {

logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");

}

}

}

}

2、根据访问URL找到对应 Controller 中处理请求的方法

/** 中央控制器,控制请求的转发 **/

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

HttpServletRequest processedRequest = request;

HandlerExecutionChain mappedHandler = null;

int interceptorIndex = -1;

try {

ModelAndView mv;

boolean errorView = false;

try {

    // 1.检查是否是文件上传的请求

processedRequest = checkMultipart(request);

// 2.取得处理当前请求的controller,这里也称为hanlder,处理器,第一个步骤的意义就在这里体现了.

这里并不是直接返回controller,而是返回的HandlerExecutionChain请求处理器链对象,该对象封装了handler和interceptors.

mappedHandler = getHandler(processedRequest, false);

    // 如果handler为空,则返回404

if (mappedHandler == null || mappedHandler.getHandler() == null) {

noHandlerFound(processedRequest, response);

return;

}

//3. 获取处理request的处理器适配器handler adapter

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// 处理 last-modified 请求头

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;

}

}

// 4.拦截器的预处理方法

HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();

if (interceptors != null) {

for (int i = 0; i < interceptors.length; i++) {

HandlerInterceptor interceptor = interceptors[i];

if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {

triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);

return;

}

interceptorIndex = i;

}

}

// 5.实际的处理器处理请求,返回结果视图对象

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

// 结果视图对象的处理

if (mv != null && !mv.hasView()) {

mv.setViewName(getDefaultViewName(request));

}

// 6.拦截器的后处理方法

if (interceptors != null) {

for (int i = interceptors.length - 1; i >= 0; i--) {

HandlerInterceptor interceptor = interceptors[i];

interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);

}

}

}

catch (ModelAndViewDefiningException ex) {

logger.debug("ModelAndViewDefiningException encountered", ex);

mv = ex.getModelAndView();

}

catch (Exception ex) {

Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);

mv = processHandlerException(processedRequest, response, handler, ex);

errorView = (mv != null);

}

if (mv != null && !mv.wasCleared()) {

render(mv, processedRequest, response);

if (errorView) {

WebUtils.clearErrorRequestAttributes(request);

}

}

else {

if (logger.isDebugEnabled()) {

logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +

"': assuming HandlerAdapter completed request handling");

}

}

// 请求成功响应之后的方法

triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);

}

3、反射调用处理请求的方法返回结果视图

/** 获取处理请求的方法,执行并返回结果视图 **/

protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

  // 1.获取方法解析器

ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);    

// 2.解析request中的url,获取处理request的方法

//通过 request 找 controller 中的处理方法,request的url与 controller 的url 进行匹配

Method handlerMethod = methodResolver.resolveHandlerMethod(request);    

// 3.方法调用器

ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);

ServletWebRequest webRequest = new ServletWebRequest(request, response);

ExtendedModelMap implicitModel = new BindingAwareModelMap();

     // 4.执行方法

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

// 5.封装结果视图

ModelAndView mav =

methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);

methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);

return mav;

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:讲解ssm框架整合(最通俗易懂)
下一篇:Java负载均衡服务器实现上传文件同步
相关文章

 发表评论

暂时没有评论,来抢沙发吧~