一文讲述Spring MVC的执行流程
【摘要】 来自官网:在网上找到的更加详细的图:我们搜索下DispatchServlet类看看有没有,果然有一个看下DispatchServlet的类关系图 1 研究DispatchServlet看下这个类的全部方法,不用想一定会有一个类似于Servlet中的service方法,果然如此 1.1 DispatchServlet的doService方法在doService方法中一定是主要处理业务请求的@O...
来自官网:
在网上找到的更加详细的图:
我们搜索下DispatchServlet类看看有没有,果然有一个
看下DispatchServlet的类关系图
1 研究DispatchServlet
看下这个类的全部方法,不用想一定会有一个类似于Servlet中的service方法,果然如此
1.1 DispatchServlet的doService方法
在doService方法中一定是主要处理业务请求的
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 记录日志
logRequest(request);
// 保留请求属性的快照,以便在包含之后能够恢复原始属性
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// 设置一些request的值,使框架对象对处理程序和视图对象可用
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
......
try {
//最主要的doDispatch方法
doDispatch(request, response);
}
......
}
1.2 DispatchServlet的doDispatch方法
doDispatch是被doService方法调用,是处理请求流程的一个主要方法,主要分为一下几个流程
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
......
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//检查处理Multipart请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 确定当前请求的处理,请求Handler
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 获取适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 判断请求方法
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 实际的Handler调用
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 解析ModelAndView
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
......
// 渲染视图
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
......
finally {
......
}
}
2 深入源码
2.1 怎样找到Handler的?
先写一个RequestMapping
@ResponseBody
@RequestMapping("/helloMvc")
public String helloMvc() {
return "Hello I am Spring MVC";
}
打断点,debug
请求
开始debug
点进方法内部再看看
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
// 遍历所有的request,直到最后都没有的话返回null
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
在这之后,请求就会找到对应的Handler进行处理。
2.2 Spring MVC视图解析机制
首先定义一个ViewResolver类型的List
/** List of ViewResolvers used by this servlet. */
@Nullable
private List<ViewResolver> viewResolvers;
初始化ViewResolvers
private void initViewResolvers(ApplicationContext context) {
this.viewResolvers = null;
if (this.detectAllViewResolvers) {
// 在ApplicationContext中找到所有的viewresolver,包括全部上下文
Map<String, ViewResolver> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.viewResolvers = new ArrayList<>(matchingBeans.values());
// 保持viewresolver的排序。
AnnotationAwareOrderComparator.sort(this.viewResolvers);
}
}
......
}
然后进行视图解析
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
// 判断有无异常
if (exception != null) {
// 如果异常不为空,则返回一个错误的页面
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
if (mv != null && !mv.wasCleared()) {
// 视图渲染
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
......
}
视图渲染
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 确定请求的区域设置并将其应用于响应
Locale locale =
(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// 获取视图名称
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
......
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "]", ex);
}
throw ex;
}
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)