主要基于servlet,更加简单。
重点:SpringMVC得请求处理流程:
DispatcherServlet类
// 文件处理器
private MultipartResolver multipartResolver;
// 映射器
private List<HandlerMapping> handlerMappings;
// 适配器
private List<HandlerAdapter> handlerAdapters;
// 异常处理器
private List<HandlerExceptionResolver> handlerExceptionResolvers;
// 视图解析器
private List<ViewResolver> viewResolvers;
然后我们会发现它们在initStrategies()上初始化:
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
请求进到DispatcherServlet,其实全部都会打到doService()方法上。我们看看这个doService()方法做了啥:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 设置一些上下文...(省略一大部分)
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
// 调用doDispatch
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
所以请求会走到doDispatch(request, response);里边,我们再进去看看:
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);
// 找到HandlerExecutionChain
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 得到对应的hanlder适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 拦截前置处理
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 真实处理请求
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 视图解析器处理
applyDefaultViewName(processedRequest, mv);
// 拦截后置处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
}
}
这里的流程跟我们上面的图的流程几乎是一致的了。我们从源码可以知道的是,原来SpringMVC的拦截器是在MappingHandler的时候一齐返回的,返回的是一个HandlerExecutionChain对象。这个对象也不难,我们看看:
public class HandlerExecutionChain {
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
// 真实的handler
private final Object handler;
// 拦截器List
private HandlerInterceptor[] interceptors;
private List<HandlerInterceptor> interceptorList;
private int interceptorIndex = -1;
}
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 遍历一遍默认的Handler实例,选出合适的就返回
for (HandlerMapping hm : this.handlerMappings) {
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
再进去getHandler里边看看呗,里边又有几层,我们最后可以看到它根据路径去匹配,走到了lookupHandlerMethod这么一个方法
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>();
// 获取路径
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
// 对匹配的排序,找到最佳匹配的
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
Collections.sort(matches, comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
lookupPath + "] : " + matches);
}
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
}
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
找拦截器大概也是上面的一个过程,于是我们就可以顺利拿到HandlerExecutionChain了,找到HandlerExecutionChain后,我们是先去拿对应的HandlerAdaptor。我们也去看看里边做了什么:
// 遍历HandlerAdapter实例,找到个合适的返回
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (ha.supports(handler)) {
return ha;
}
}
}
我们看一个常用HandlerAdapter实例RequestMappingHandlerAdapter,会发现他会初始化很多的参数解析器,其实我们经常用的@ResponseBody解析器就被内置在里边:
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
// ResponseBody Requestbody解析器
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), t
// 等等
return resolvers;
}
@ReponseBody让返回json
返回JSON对象,我们就需要用到@ResponseBody注解,如果接收JSON数据封装成JavaBean的话,我们就需要用到@RequestBody注解。随后在配置文件上创建对应的bean即可。
SpringMVC的工作流程:
用户发送HTTP请求,SpringMVC核心控制器接收到请求
找到映射器看该请求是否交由对应的Action类进行处理
找到适配器看有无该Action类
Action类处理完结果封装到ModelAndView中
通过视图解析器把数据解析,跳转到对应的JSP页面
-总结步骤:
1)所有请求过来DispatcherServelt收到请求
2)调用doDispatch方法处理
1》getHandler():根据当前请求地址找到能处理这个请求的目标处理器类
2》getHandlerAdapter():根据当前处理器类类获取到能执行这个处理器方法的适配器
3》使用刚才获取到的适配器执行目标方法
4》目标方法执行后返回一个ModelAndView对象
5》根据mv信息转发到具体页面,并可以在请求域中取出数据