1. 运行流程
1.1 运行主流程
DispatcherServlet#doService(){
//....
doDispatch();//主体流程
//....
}
DispatcherServlet#doDispatch(){
//....
//获取请求中指向的 Handler,返回 HandlerExecutionChain
//HandlerExecutionChain中主要两个属性,【HandlerMapping对当前handler封装对象】+【当前Handler的拦截器数组】
mappedHandler = getHandler(processedRequest);
//....
// 为当前Handler找一个合适的 HandlerAdapter,来执行此Handler
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//....
}
DispatcherServlet#getHandler() {
//遍历工厂中的 HandlerMapping, HandlerMapping中记录着Handler的访问地址
//但只有认识@RequestMapping注解的HandlerMapping,才真正记录着各个handler的访问地址
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map ...);
}
// 从HandlerMapping中获取 请求路径对应的Handler
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {//如果当前HandlerMapping可以识别当前请求,则返回
return handler;
}
}
return null;
}
DispatcherServlet#getHandlerAdapter(){
for (HandlerAdapter ha : this.handlerAdapters) {
// ....
if (ha.supports(handler)) {// 遍历多个Adapter,选择一个适合当前Handler的Adapter
return ha;
}
}
}
DispatcherServlet#doDispatch(){
//....
//获取请求中指向的 Handler,返回 HandlerExecutionChain
//HandlerExecutionChain中主要两个属性,【HandlerMapping对当前handler封装对象】+【当前Handler的拦截器数组】
mappedHandler = getHandler(processedRequest);
//....
// 为当前Handler找一个合适的 HandlerAdapter,来执行此Handler
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//....
//执行拦截器的前置逻辑
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//紧接着,执行handler,返回一个ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//.....
//执行拦截器的后置逻辑
mappedHandler.applyPostHandle(processedRequest, response, mv);
//.....
//视图渲染,在此方法内部解析完视图渲染后,会调用:
// mappedHandler.triggerAfterCompletion(request, response, null);//拦截器的最终逻辑
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
// processDispatchResult会调用此方法,进行视图渲染
DispatcherServlet#render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response){
// ....
// 解析出一个View对象,其实此View已经在ModelAndView中,在ha执行完handler后就存在了
View view = resolveViewName(...);
// ....
// 调用View的渲染方法,内部将跳转视图,并响应请求
view.render(....);
// 常见的View类型:InternalResourceView用户处理转发跳转,内部使用 request.getRequestDispatcher().forward()
// RedirectView 用于处理重定向,内部使用 response.sendRedirect()
}
1.2 启动细节
第一次访问时,DispatcherServlet启动,启动中会初始化很多,系统组件( HandlerMapping, HandlerAdapter … ),以及所有Controller。
ComponentScanBeanDefinitionParser 负责解析配置中的 context:component-scan,并扫描Controller,并创建
AnnotationDrivenBeanDefinitionParser 负责解析配置中的 mvc:annotation-driven,并创建对应组件
1.3 HandlerMapping 解析请求细节
每种HandlerMapping都有一方法getHandlerInternal(request)为当前请求匹配并返回一个Handler,
但返回类型不一。所谓返回类型不一,是指如果找到匹配的Handler,封装的方法不同,即封装后的对象类型不同。
比如RequestMappingHandlerMapping的返回的是一个HandlerMethod
比如BeanNameUrlHandlerMapping的返回直接是一个Controller对象
细节:
RequestMappingHandlerMapping中的getHandler方法,会调用getHandlerInternal()返回一个 HandlerMethod; 在getHandler方法中再封装进一个HandlerExecutionChain中。
BeanNameUrlHandlerMapping中的getHandler方法,会调用getHandlerInternal()方法,方法中会先找到对应的Controller类,然后直接封装为HandlerExecutionChain,并返回给getHandler方法。
HandlerExecutionChain 中主要封装两类信息:当前handler 、handler的拦截器数组。
@Controller("/abc")//不能定义多方法,且 "/abc"既是beanId,更是访问路径。BeanNameUrlHandlerMapping可以解析
public class CaptchaController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response)
throws Exception {
ModelAndView mav = new ModelAndView("index");
return mav;
}
}
1.4 HandlerAdapter解析Handler细节
HandlerExecutionChain在得到后,会遍历所有HandlerAdapter,通过调用HandlerAdapter中的supports(),判断哪个HandlerAdapter可以解析当前HandlerExecutionChain中持有的handler。
RequestMappingHandlerAdapter 可以识别 HandlerMethod,所以和RequestMappingHandlerMapping是一个组合
SimpleControllerHandlerAdapter 可以识别Controller类,所以和 BeanNameUrlHandlerMapping是一个组合
综上,HandlerMapping和HandlerAdapter是配套使用的。
ops:可以断点在DispatcherServlet的doDispatch方法中,
然后查看DispatcherServlet的 handlerMappings 和 handlerAdapters属性
2. SpringMVC工厂启动
DispatcherServlet父类的父类:
HttpServletBean#init(){
//....
// Let subclasses do whatever initialization they like.
initServletBean();//初始化
//....
}
FrameworkServlet#initServletBean(){
//....
this.webApplicationContext = initWebApplicationContext();//初始化工厂
//....
}
FrameworkServlet#initFrameworkServlet(){
//获取Spring工厂,准备将其作为父容器
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
//....
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
}
//....
}
FrameworkServlet#createWebApplicationContext(){
return createWebApplicationContext((ApplicationContext) parent);
}
FrameworkServlet#createWebApplicationContext(xx){
//....
// 创建springMVC工厂对象:XmlWebApplicationContext
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());//设置环境参数
wac.setParent(parent);//将spring容器,作为自己的父容器
wac.setConfigLocation(getContextConfigLocation());//设置配置文件位置
configureAndRefreshWebApplicationContext(wac);//启动SpringMVC工厂,创建其中的bean
return wac;
}
//如上的启动过程中 configureAndRefreshWebApplicationContext(wac),会执行到:
DispatcherServlet#initStrategies(ApplicationContext context) {
initMultipartResolver(context);//初始化上传解析器
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);//初始化 HandlerMappings
initHandlerAdapters(context);//初始化 HandlerAdapters
initHandlerExceptionResolvers(context);//初始化 异常解析器
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
3. Json处理
3.1 响应
View InternalResourceView(JSTlView) RedirectView FastJsonView xxxJacksonView
Json响应是靠 HttpMessageConverter,而不是View!!
// 使用了@ResponseBoy 后,Handler执行后不再返回一个ModelAndView,
// 而是在 前端控制器触发Handler执行时,handler执行的最后一步就已经响应了。所以没有后续的View过程。
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());//从此处开始执行Handler
FastJsonHttpMessageConverter#writeInternal(){
ByteArrayOutputStream outnew = new ByteArrayOutputStream();//字节输出流
//......
//将转换后的json,存入outnew
int len = JSON.writeJSONString(outnew, //
fastJsonConfig.getCharset(), //
value, //
fastJsonConfig.getSerializeConfig(), //
//fastJsonConfig.getSerializeFilters(), //
allFilters.toArray(new SerializeFilter[allFilters.size()]),
fastJsonConfig.getDateFormat(), //
JSON.DEFAULT_GENERATE_FEATURE, //
fastJsonConfig.getSerializerFeatures());
// ....
// outnew将内容输出给 response.getOutputStream()
outnew.writeTo(outputMessage.getBody());// outputMessage是response对象,getBody中
// response.getOutputStream()
}
AbstractJackson2HttpMessageConverter#writeInternal(){
// ....
// 获得一个可以响应json的generator response.getOutputStream()
JsonGenerator gene = this.objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);
// ....
// 将json响应到客户端
objectWriter.writeValue(generator, value);
}
3.2 收参
@RequestBody收参时,会调用如下核心方法,实现从json到java对象的转换
AbstractJackson2HttpMessageConverter#read(){//将json转换为java对象
//....
}
FastJsonHttpMessageConverter#read(){//将json转换为java对象
//....
}
@RequestMapping(value="/users",method = RequestMethod.PUT)
@ResponseBody
public MyRequestStatus updateUser(@RequestBody User user) {
System.out.println("update One user:"+user);
MyRequestStatus status = new MyRequestStatus("update", "ok");
return status;
}
执行流程 DispatcherServlet 接收到请求后 找到一个可以识别当前路径的HandlerMappping
通过请求路径返回HandlerChain然后执行 HandlerChain 会依次调用拦截器的方法和Handler 并完成请求参数
的封装 和相应JSON时(HttpMessageConverter) 的格式转化 handler 执行完毕 返回ModelAndVIew ViewResolver
通过ModeAndView中的viewName解析出一个View 对象 VIew完成转发或从定向 到jsp层
静态资源的访问 mvc:default-servlet-handler/