简述SprintMVC过程

SprintMVC

SpringMVC是一个对servlet进行大量封装的Spring框架的组件,,基于MCV架构模式,用于表现层的开发。

SpringMVC中包含两个容器,Spring作为父容器,SpringMVC作为子容器。

简略过程

通过映射器找到url对应的控制器,但控制器需要实现处理器的接口,且有多种方式实现,因此需要适配器确定是哪个处理器接口,确定好处理器接口后,可以直接调用控制器重写的方法,完成控制器的逻辑并返回ModelAndView给DispatcherServlet,DispatcherServlet通过视图解析器将逻辑视图名匹配到视图,然后通过浏览器渲染展示。

= Spring容器和SpringMVC容器启动

= 遍历处理器映射器,获取请求对应的处理器执行链(封装的handler和interceptor)

= 遍历处理器适配器,获取支持处理器的处理器适配器

= 调用适配器的handle方法,执行控制器实现处理器接口的重写方法,完成控制器的逻辑,返回ModelAndView

= 根据ModelAndView获取到Model和View对象,合并Model的数据和request属性,然后对view进行渲染,响应到浏览器

public class DispatcherServlet extends FrameworkServlet {
    private List<HandlerMapping> handlerMappings;
    
}

1、MVC容器启动

// 创建、加载Spring配置并刷新Spring容器(Root WebApplicationContext)
ContextLoader#initWebApplicationContext()
// 初始化Servlet相关的bean,创建并刷新SpringMVC容器
FrameworkServlet#initServletBean()

.......

2、初始化DispatcherServlet策略接口

【通过发布事件及事件监听处理器来】初始化MVC九大组件(DispatcherServlet策略接口) ,DispatcherServlet.properties文件中默认配置了DispatcherServlet策略接口的实现类。

// 初始化HandlerMapping、HandlerAdapter和ViewResolver
protected void initStrategies(ApplicationContext context){
	// 开启detectAll,获取HandlerMapping类型的bean,赋值给handlerMappings列表
    // 关闭detectAll,获取beanName为handlerMapping且类型为HandlerMapping的bean, 赋值给handlerMappings列表
    // handlerMappings==null,获取默认策略的实现类, 赋值给handlerMappings列表
	initHandlerMappings(context);
    // 开启detectAll,获取HandlerAdapter类型的bean,赋值给handlerAdapters列表
    // 关闭detectAll,获取beanName为handlerAdapter且类型为HandlerAdapter的bean, 赋值给handlerAdapters列表
    // handlerAdapters==null,获取默认策略的实现类, 赋值给handlerAdapters列表
    initHandlerAdapters(context);
	// 同上面类似
    initViewResolvers(context);
}

3、请求处理流程

SpringMVC遵循Servlet的生命周期,Servlet生命周期主要有三个重要的方法init()、service()、destory()。

FrameworkServlet#service()		# 接收请求
FrameworkServlet#processRequest()	# 处理LocaleContext和ServletRequestAttributes
FrameworkServlet#doService()	# 
DispatcherServlet#doService()	# 设置HttpServletRequest属性
DispatcherServlet#doDispatch()	# 请求分发【处理实际的请求,分发给handler】

Process the actual dispatching to the handler.

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 从HandlerMapping中获取当前请求对应的HandlerExecutionChain对象 (handler and any interceptors)
	HandlerExecutionChain mappedHandler = getHandler(processedRequest);
    
    // 从HandlerExecutionChain拿到handler对象,再获取handler对应的HandlerAdapter对象
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
    // Apply preHandle methods of registered interceptors.
    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
        return;
    }
    
    // Actually invoke the handler,返回ModelAndView
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
    // view==null,根据request设置默认的view名
    applyDefaultViewName(processedRequest, mv);
    
    // Apply postHandle methods of registered interceptors.
    mappedHandler.applyPostHandle(processedRequest, response, mv);
    
    //处理分发结果
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        
}

getHandler方法中返回请求的HandlerExecutionChain对象

public interface HandlerMapping {
    // Return a handler and any interceptors for this request. 
    // The choice may be made on request URL, session state, 
    // or any factor the implementing class chooses.
    @Nullable
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
    
}
控制器
  • ParameterizableViewController:请求路径url直接到视图
  • AbstractCommandController:

SpringMVC中重写处理器(handle)的三种方式:

  1. 实现HttpRequestHandler接口,重写handleRequest方法
public class TestController implements HttpRequestHandler {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        return null;
    }
}
  1. 实现Controller接口,重写handleRequest方法
public class TestController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        return null;
    }
}
  1. @Controller注解
@Controller
public class TestController {
}
映射器

HandlerMapping的三个实现类

DispatcherServlet#doDispatch()
-->DispatcherServlet#getHandler() // 遍历handlerMappings,返回request的HandlerExecutionChain对象(handler and any interceptors)
 -->AbstractHandlerMapping#getHandler() // 获取请求的handler,返回获得的HandlerExecutionChain对象,处理跨域问题
  -->AbstractHandlerMethodMapping#getHandlerInternal() // 查找请求的最优匹配handler method,返回HandlerMethod对象
  -->AbstractHandlerMethodMapping#lookupHandlerMethod() // 返回请求对应的HandlerMethod对象(Controller的beanName、Class对象、method...)
   -->HandlerMethod#createWithResolvedBean() //  获取Controller的beanName,返回 封装handler(Controller)的HandlerMethod对象
  -->AbstractHandlerMapping#getHandlerExecutionChain() // 创建处理器执行链对象,封装handler处理器和添加匹配请求的interceptor拦截器 
    
RequestMappingHandlerMapping#afterPropertiesSet() // RequestMappingInfo.BuilderConfiguration 属性赋值
 -->AbstractHandlerMethodMapping#initHandlerMethods() // Scan beans in the ApplicationContext
 -->AbstractHandlerMethodMapping#processCandidateBean()	// 处理被Controller、RequestMapping注解修饰bean
 -->AbstractHandlerMethodMapping#detectHandlerMethods() // 获取访问路径与控制器方法的映射关系
 -->AbstractHandlerMethodMapping#registerHandlerMethod() // Register a handler method and its unique mapping
适配器

适配器根据supports()判断控制器实现了哪个处理器接口,最后调用控制器重写实现处理器接口的方法,完成控制器的逻辑,返回ModelAndView

DispatcherServlet#doDispatch()
-->DispatcherServlet#getHandlerAdapter() // 遍历handlerAdapters,返回supports(handler)的HandlerAdapter
// 调用HandlerAdapter的handle()方法,完成控制器的逻辑
-->RequestMappingHandlerAdapter#handleInternal()
-->RequestMappingHandlerAdapter#invokeHandlerMethod() // Invoke the RequestMapping handler method preparing a ModelAndView...
-->RequestMappingHandlerAdapter#createInvocableHandlerMethod() // 参数绑定、处理请求以及返回值处理

......
视图解析器

通过ModelAndView对象解析出View对象并且获取Model对象,将Model对象的数据和request的属性合并为mergedModel, 然后设置mergedModel到request属性中;确定request dispatcher的路径,获取请求分发器(RequestDispatcher)进行转发

DispatcherServlet#doDispatch()
-->DispatcherServlet#processDispatchResult() // 处理异常的ModelAndView对象,渲染页面,触发Interceptor的afterCompletion
-->DispatcherServlet#render() // 获取View对象,设置响应状态码,页面渲染,
-->DispatcherServlet#resolveViewName() // 遍历viewResolvers,根据视图名称,解析出View对象

......
posted @ 2023-09-05 21:32  jishaleng  阅读(15)  评论(0编辑  收藏  举报