前文:这一篇幅我们主要来讲解一下Spring Mvc的请求流程,看看Spring框架是如何和Servlet进行整合,然后进行处理请求的。按照惯例,我们还是来说明一下重要的接口和类。
一、本篇幅解析源码用到的接口和类。
1、DispatcherServlet 它是SpringMVC中的前端控制器(front controller),负责接收request并将request转发给对应的处理组件。2、HanlerMapping 它是SpringMVC中完成url到Controller映射的组件。DispatcherServlet接收request,然后从HandlerMapping查找处理request的controller.
3、HandlerExecutionChain handler具体的执行器的一层包装类。
4、AnnotationMethodHandlerAdapter 处理器适配器,进行处理器中方法的调用。
5、ModelAndView ”模型和视图“,可以理解成MVC架构中的”M“和”V“。
二、源码分析。
上图流程总体来说可分为三大块:
Map的建立(并放入WebApplicationContext)
HttpRequest请求中Url的请求拦截处理(DispatchServlet处理)
反射调用Controller中对应的处理方法,并返回视图
本文将围绕这三块进行分析。
1. Map的建立
在容器初始化时会建立所有 url 和 Controller 的对应关系,保存到 Map<url,controller>中,那是如何保存的呢。
ApplicationObjectSupport #setApplicationContext方法
// 初始化ApplicationContext
@Override
public void initApplicationContext() throws ApplicationContextException {
super.initApplicationContext();
detectHandlers();
}
AbstractDetectingUrlHandlerMapping #detectHandlers()方法:
/**
* 建立当前ApplicationContext 中的 所有Controller 和url 的对应关系
*/
protected void detectHandlers() throws BeansException {
if (logger.isDebugEnabled()) {
logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
}
// 获取容器中的beanNames
String[] beanNames = (this.detectHandlersInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
// 遍历 beanNames 并找到对应的 url
// Take any bean name that we can determine URLs for.
for (String beanName : beanNames) {
// 获取bean上的url(class上的url + method 上的 url)
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
// URL paths found: Let's consider it a handler.
// 保存url 和 beanName 的对应关系
registerHandler(urls, beanName);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
}
}
}
}
determineUrlsForHandler()方法:
该方法在不同的子类有不同的实现,我这里分析的是DefaultAnnotationHandlerMapping类的实现,该类主要负责处理@RequestMapping注解形式的声明。
/**
* 获取@RequestMaping注解中的url
*/
@Override
protected String[] determineUrlsForHandler(String beanName) {
ApplicationContext context = getApplicationContext();
Class<?> handlerType = context.getType(beanName);
// 获取beanName 上的requestMapping
RequestMapping mapping = context.findAnnotationOnBean(beanName, RequestMapping.class);
if (mapping != null) {
// 类上面有@RequestMapping 注解
this.cachedMappings.put(handlerType, mapping);
Set<String> urls = new LinkedHashSet<String>();
// mapping.value()就是获取@RequestMapping注解的value值
String[] typeLevelPatterns = mapping.value();
if (typeLevelPatterns.length > 0) {
// 获取Controller 方法上的@RequestMapping
String[] methodLevelPatterns = determineUrlsForHandlerMethods(handlerType);
for (String typeLevelPattern : typeLevelPatterns) {
if (!typeLevelPattern.startsWith("/")) {
typeLevelPattern = "/" + typeLevelPattern;
}
for (String methodLevelPattern : methodLevelPatterns) {
// controller的映射url+方法映射的url
String combinedPattern = getPathMatcher().combine(typeLevelPattern, methodLevelPattern);
// 保存到set集合中
addUrlsForPath(urls, combinedPattern);
}
addUrlsForPath(urls, typeLevelPattern);
}
// 以数组形式返回controller上的所有url
return StringUtils.toStringArray(urls);
}
else {
// controller上的@RequestMapping映射url为空串,直接找方法的映射url
return determineUrlsForHandlerMethods(handlerType);
}
}
// controller上没@RequestMapping注解
else if (AnnotationUtils.findAnnotation(handlerType, Controller.class) != null) {
// 获取controller中方法上的映射url
return determineUrlsForHandlerMethods(handlerType);
}
else {
return null;
}
}
到这里,Controller和Url的映射就装配完成,下来就分析请求的处理过程。
2. url的请求处理
我们在xml中配置了DispatcherServlet为调度器,所以我们就来看它的代码,可以
从名字上看出它是个Servlet,那么它的核心方法就是doService()
DispatcherServlet #doService():
/**
* 将DispatcherServlet特定的请求属性和委托 公开给{@link #doDispatch}以进行实际调度。
*/
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String requestUri = new UrlPathHelper().getRequestUri(request);
logger.debug("DispatcherServlet with name '" + getServletName() + "' processing " + request.getMethod() +
" request for [" + requestUri + "]");
}
//在包含request的情况下保留请求属性的快照,
//能够在include之后恢复原始属性。
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
logger.debug("Taking snapshot of request attributes before include");
attributesSnapshot = new HashMap<String, Object>();
Enumeration attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// 使得request对象能供 handler处理和view处理 使用
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
try {
doDispatch(request, response);
}
finally {
// 如果不为空,则还原原始属性快照。
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
可以看到,它将请求拿到后,主要是给request设置了一些对象,以便于后续工作的处理(Handler处理和view处理)。比如WebApplicationContext,它里面就包含了我们在第一步完成的controller与url映射的信息。
DispatchServlet # doDispatch()
/**
* 控制请求转发
*/
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);
// Determine handler for the current request.
// 2. 获取handler处理器,返回的mappedHandler封装了handlers和interceptors
mappedHandler = getHandler(processedRequest, false);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
// 返回404
noHandlerFound(processedRequest, response);
return;
}
// Apply preHandle methods of registered interceptors.
// 获取HandlerInterceptor的预处理方法
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;
}
}
// Actually invoke the handler.
// 3. 获取handler适配器 Adapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 4. 实际的处理器处理并返回 ModelAndView 对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// Do we need view name translation?
if (mv != null && !mv.hasView()) {
mv.setViewName(getDefaultViewName(request));
}
// HandlerInterceptor 后处理
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);
}
// Did the handler return a view to render?
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");
}
}
// Trigger after-completion for successful outcome.
// 请求成功响应之后的方法
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
}
catch (Exception ex) {
// Trigger after-completion for thrown exception.
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
throw ex;
}
catch (Error err) {
ServletException ex = new NestedServletException("Handler processing failed", err);
// Trigger after-completion for thrown exception.
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
throw ex;
}
finally {
// Clean up any resources used by a multipart request.
if (processedRequest != request) {
cleanupMultipart(processedRequest);
}
}
}
该方法主要是以下几个功能:
-
通过request对象获取到HandlerExecutionChain,HandlerExecutionChain对象里面包含了拦截器interceptor和处理器handler。如果获取到的对象是空,则交给noHandlerFound返回404页面。
-
拦截器预处理,如果执行成功则进行3
-
获取handler适配器 Adapter
-
实际的处理器处理并返回 ModelAndView 对象
3. 反射调用处理请求的方法,返回结果视图
在上面的源码中,实际的处理器处理并返回 ModelAndView 对象调用的是mv = ha.handle(processedRequest, response, mappedHandler.getHandler());这个方法。该方法由AnnotationMethodHandlerAdapter #handle() #invokeHandlerMethod()方法实现。
AnnotationMethodHandlerAdapter #handle() #invokeHandlerMethod()
/**
* 获取处理请求的方法,执行并返回结果视图
*/
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 1.获取方法解析器
ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
// 2.解析request中的url,获取处理request的方法
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. 封装成mv视图
ModelAndView mav =
methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
return mav;
}
三、总结。
我们队Spring mvc的整体流程进行概括。其实理解这些才是最重要的。
1、用户发送请求至前端控制器DispatcherServlet
2、DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
5、HandlerAdapter执行处理器(handler,也叫后端控制器)。
6、Controller执行完成返回ModelAndView
7、HandlerAdapter将handler执行结果ModelAndView返回给DispatcherServlet
8、DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9、ViewReslover解析后返回具体View对象
10、DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。DispatcherServlet响应用户