今天来探索SpringMVC一次请求过程的源码,首先需要找到程序运行的类及主要方法:
我们使用StringMVC首先需要在web.xml中设置一个前端控制器来处理请求,这个前端控制器是:org.springframework.web.servlet.DispatcherServlet
调用本类的processRequest方法
调用本类的doService方法
调用 DispatherServlet的doDispatch方法处理请求,主要程序在此方法中进行
到这里我们可以看出这个前端控制器主要工作是在 DispatherServlet的 doDispatch方法中完成。
大致流程如下:
决定使用那个适配器处理请求(适配器模式)
执行预处理方法
使用适配器执行目标方法,返回ModleAndView
执行目标后处理方法
处理业务逻辑执行以后的返回结果,即处理视图,
调用本类的render(mv, request, response);渲染视图。是将方法的返回值,最终变为一个View对象。
这个View对象正是我们在xml中配置的InternalResourceView
调用 AbstractView类中的render方法
调用 InternalResourceView类中的renderMergedOutputModel方法进行渲染模型、转发操作:
我们使用StringMVC首先需要在web.xml中设置一个前端控制器来处理请求,这个前端控制器是:org.springframework.web.servlet.DispatcherServlet
那么我们程序运行的入口就在这里。
从这里可以看出前端控制器是一个Servlet,我们寻找他的service方法,在DispatherServlet中并没有找到service方法,在其父类FrameworkServlet中找到service方法。如下:
FrameworkServlet:
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String method = request.getMethod();
if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {
// 处理请求
processRequest(request, response);
}
else {
super.service(request, response);
}
}
调用本类的processRequest方法
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
initContextHolders(request, localeContext, requestAttributes);
try {
// 调用doService方法处理请求
doService(request, response);
}
...
调用本类的doService方法
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
try {
// 调用doDispatch方法处理请求
doDispatch(request, response);
}
...
调用 DispatherServlet的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 {
processedRequest = checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// Determine handler for the current request.
// 通过processedRequest,决定使用哪个handler来处理请求
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 决定使用那个适配器处理请求(适配器模式)
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.
// 使用适配器执行目标方法,返回ModleAndView
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;
}
// 处理业务逻辑执行以后的返回结果,即处理视图
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);
}
}
}
到这里我们可以看出这个前端控制器主要工作是在 DispatherServlet的 doDispatch方法中完成。
大致流程如下:
通过processedRequest,决定使用哪个handler来处理请求
HandlerExecutionChain mappedHandler = null;
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
决定使用那个适配器处理请求(适配器模式)
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
执行预处理方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
使用适配器执行目标方法,返回ModleAndView
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
执行目标后处理方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
处理业务逻辑执行以后的返回结果,即处理视图,
调用本类的processDispatchResult方法
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
...
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);//渲染视图
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
..
调用本类的render(mv, request, response);渲染视图。是将方法的返回值,最终变为一个View对象。
这个View对象正是我们在xml中配置的InternalResourceView
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
..
// Determine locale for request and apply it to the response.
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
// View对象
View view;
if (mv.isReference()) {
// We need to resolve the view name.
view = resolveViewName(mv.getViewName(), 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对象
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() + "'");
}
}
// Delegate to the View object for rendering.
if (logger.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
try {
// 内部视图解析器继续解析视图:
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '"
+ getServletName() + "'", ex);
}
throw ex;
}
}
调用 AbstractView类中的render方法
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
" and static attributes " + this.staticAttributes);
}
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
prepareResponse(request, response);
// 渲染模型
renderMergedOutputModel(mergedModel, request, response);
}
调用 InternalResourceView类中的renderMergedOutputModel方法进行渲染模型、转发操作:
//拿到转发器,进行转发
@Override
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine which request handle to expose to the RequestDispatcher.
HttpServletRequest requestToExpose = getRequestToExpose(request);
// Expose the model object as request attributes.
exposeModelAsRequestAttributes(model, requestToExpose);
// Expose helpers as request attributes, if any.
exposeHelpers(requestToExpose);
// Determine the path for the request dispatcher.
String dispatcherPath = prepareForRendering(requestToExpose, response);
//获得转发器
// Obtain a RequestDispatcher for the target resource (typically a JSP).
RequestDispatcher rd = getRequestDispatcher(requestToExpose, dispatcherPath);
if (rd == null) {
throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
"]: Check that the corresponding file exists within your web application archive!");
}
// If already included or response already committed, perform include, else forward.
if (useInclude(requestToExpose, response)) {
response.setContentType(getContentType());
if (logger.isDebugEnabled()) {
logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
rd.include(requestToExpose, response);
}
else {
// Note: The forwarded resource is supposed to determine the content type itself.
if (logger.isDebugEnabled()) {
logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
//进行转发
rd.forward(requestToExpose, response);
}
}