SpringMVC被广泛应用到企业级web应用程序开发上面,下面我们来看看它究竟有何魅力。
不管是structs还是springmvc,首先从web开发地核心上讲是在原有地servlet处理方式上做了很多包装和增加了很多便捷开发地功能。SpringMVC被广为人知的很重要的一点就是它有一个中央控制器,说到这里就得提一下设计模式,其实很多设计模式都可以看作是第三者操作模式,所谓第三者就是在原有的功能模块上增加了一个控制台,比如说工厂模式,通过这种方式达到松耦合的目的。下面是我自己画的一个简图:
所有的操作流程在SpringMVC框架里面都是跟DispatcherServlet直接相关的。
在接收到客户端的resquest请求后,第一步是从HandlerMapping对象里得到相应的Handler(就是平常写的Controller),这个HandlerMapping在没有注解支持的时候最常见的方式是在xml文件里面配置,在有了注解之后基本上都是用的RequestMappingHandlerMapping。它的作用可以纯粹的理解为是将resquest里面传来的url映射到相应的我们自己写的handler然后执行相应的操作。在DispatcherServlet源码里面返回的并不是一个纯粹的handler:
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception
在返回的实例中实际上是加了很多interceptor.获取到handler实例之后交给处理器适配器,返回一个modelAndView,最后再交给View的视图解析器给之渲染,最后返回给控制台再提交给用户。每种类都只是纯粹的干同一件事,大大减少了耦合也提高了代码的可读性和扩展性。
在DispatcherServlet类里比较重要的方法是doService和doDispatch:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (this.logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";//异步通信是有缓存效果的
this.logger.debug("DispatcherServlet with name '" + this.getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
Map<String, Object> attributesSnapshot = null; //快照---缓存
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap();
Enumeration attrNames = request.getAttributeNames();
label108: //break的高级用法,常用于多层循环跳出
while(true) {
String attrName;
do {
if (!attrNames.hasMoreElements()) {
break label108;
}
attrName = (String)attrNames.nextElement();
} while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource()); //属性注入
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);//获取可能存在的缓存状态
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
this.doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot); //再存一遍
}
}
}
可以看到doService方法里面直接调用了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 { //处理核心
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = this.checkMultipart(request); //尝试拆分请求
multipartRequestParsed = processedRequest != request; //的确是包含多个请求
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());//此时已经获取到相应的handler
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) { //如果是get请求
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (this.logger.isDebugEnabled()) {
this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); //通过适配器返回一个modelAndView
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);//执行handler (其中包含拦截器的postHandler操作)
} catch (Exception var19) {
dispatchException = var19;
}
this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);//保证mv不为空视图后执行render
} catch (Exception var20) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var20);
} catch (Error var21) {
this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var21);
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
拦截器中的postHandler会在DispatcherServlet进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView对象进行操作。渲染的操作是通过View的对象(这里使用的view是在配置文件里指定好的InternalResourceResolved)执行的,主要通过view.render(mv.getModelInternal(), request, response);操作对象。