如何评价DJI大疆创新科技有限公司的Phantom 4 Pro

SpringMVC转发时如何传递ModelAndView
编辑:晓宇
阅读:(17599)
关键字词:SpringMVC,转发,传递,ModelAndView
有空帮我喂下仓鼠,谢谢!
博客已稳定运行spring MVC之构造ModelAndView对象 - fhd001 - ITeye技术网站
博客分类:
spring MVC之构造ModelAndView对象
----------
构造ModelAndView对象
当控制器处理完请求时,通常会将包含视图名称或视图对象以及一些模型属性的ModelAndView对象返回到DispatcherServlet。因此,经常需要在控制器中构造ModelAndView对象。ModelAndView类提供了几个重载的构造器和一些方便的方法,让你可以根据自己的喜好来构造ModelAndView对象。这些构造器和方法以类似的方式支持视图名称和视图对象。
当你只有一个模型属性要返回时,可以在构造器中指定该属性来构造ModelAndView对象:
package com.apress.springrecipes.court.
import org.springframework.web.servlet.ModelAndV
import org.springframework.web.servlet.mvc.AbstractC
public class WelcomeController extends AbstractController{
public ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response)throws Exception{
Date today = new Date();
return new ModelAndView("welcome","today",today);
如果有不止一个属性要返回,可以先将它们传递到一个Map中再来构造ModelAndView对象。
package com.apress.springrecipes.court.
import org.springframework.web.servlet.ModelAndV
import org. springframework.web.servlet.mvc.AbstractC
public class ReservationQueryController extends AbstractController{
public ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response)throws Exception{
Map&String,Object& model = new HashMap&String,Object&();
if(courtName != null){
model.put("courtName",courtName);
model.put("reservations",reservationService.query(courtName));
return new ModelAndView("reservationQuery",model);
Spring也提供了ModelMap,这是java.util.Map实现,可以根据模型属性的具体类型自动生成模型属性的名称。
package com.apress.springrecipes.court.
import org.springframework.ui.ModelM
import org.springframework.web.servlet.ModelAndV
import org.springframework.web.servlet.mvc.AbstractC
public class ReservationQueryController extends AbstractController{
public ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response)throws Exception{
ModelMap model = new ModelMap();
if(courtName != null){
model.addAttribute("courtName",courtName);
model.addAttribute("reservations",reservationService.query(courtName));
return new ModelAndView("reservationQuery",model);
由于这两个模型属性的类型为String和List&Reservation&,ModelMap会为它们生成默认的名称----string和reservationList。如果你不喜欢这些名称,可以显式地指定它们。
构造完ModelAndView对象之后,仍然可以利用addobject()方法为它添加模型属性。这个方法返回ModelAndView对象
本身,因此可以在一个语句中构造ModelAndView对象。请注意,你也可以省略addObject()方法的属性名称。在这种情况下,这个方法会与ModeMap生成相同的属性名称。
package com.apress.springrecipes.court.
import org.springframework.web.servlet.ModelAndV
import org.springframework.web.servlet.mvc.AbstractC
public class ReservationQueryController extends AbstractController{
public ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response)throws Exception{
List&Reservation& reservations =
if(courtName != null){
reservations = reservationService.query(courtName);
return new ModelAndView("reservationQuery","courtName",courtName)
.addObject("reservations",reservations);
事实上,返回的模型和视图都是可选的。在有些情况下,你只返回视图,模型中没有任何属性。或者只返回模型,让Spring MVC根据请求URL来决定视图。有时候,如果让控制器直接处理HttpServletResponse对象,甚至可以返回null,例如在将二进制文件返回给用户的时候。
浏览 51069
浏览: 681850 次
来自: 杭州
不错,谢谢!
讲得非常好
我这样做的时候传中文怎么是乱码那?8、SpringMVC源码分析(3):分析ModelAndView的形成过程 - 推酷
8、SpringMVC源码分析(3):分析ModelAndView的形成过程
首先,我们还是从
DispatcherServlet
.doDispatch(
HttpServletRequest
HttpServletResponse
response) throws
Exception方法开始,看看这个牛逼的ModelAndView是怎么开始的,又是怎么结束的:
1 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest =
HandlerExecutionChain mappedHandler =
boolean multipartRequestParsed =
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
ModelAndView mv =
Exception dispatchException =
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
// 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()) {
logger.debug(&Last-Modified value for [& + getRequestUri(request) + &] is: & + lastModified);
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
// Actually invoke the handler.调用handler方法,返回ModelAndView类型的对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
// 设置mv的Object view属性值,是一个String类型(依据request的URI计算,加上一个前缀和后缀得到)
applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
catch (Exception ex) {
dispatchException =
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
从上面的源代码可以看出,mv是在调用handler方法的时候返回的(即便,我们@RequestMapping注解标识的handler方法很多时候返回的是一个String,或者是View类型。但是,反射是无所不能的,你懂的...)。我们知道,@RequestMapping标注的handler方法通常能够返回三种类型的结果:String,ModelAndView和View。从上面的ha.handle方法我们知道,动态代理最后都会将结果转化成ModelAndView类型。
一、得到mv
mv = ha.handle(processedRequest, response, mappedHandler.getHandler())
方法中如何得到mv实例的演变过程进行分析:
中分析ha.handle方法的流程时我们知道:
①、HandlerAdapter是一个接口类型;
②、AbstractHandlerMethodAdapter是一个抽象类,该抽象类实现了HandlerAdapter接口;
③、AbstractHandlerMethodAdapter的handle是一个public final类型的具体方法,此方法直接调用了AbstractHandlerMethodAdapter中protected abstract类型的抽象方法handleInternal(该方法由具体的子类来实现);
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler())语句会从
mappedHandler
队列中找到第一个能够处理该请求的
HandlerAdapter
的具体实现的一个实例,将其向上转型为
HandlerAdapter
并且赋值给ha;
⑤、@RequestMapping标注的handler方法都由RequestMappingHandlerAdapter来处理,这个Adapter继承自抽象类AbstractHandlerMethodAdapter。所以,AbstractHandlerMethodAdapter.handleInternal方法由
RequestMappingHandlerAdapter
handleInternal
⑥、总结上面①~⑤的分析,我们可以得出这样一个简单的结论:doDispatch中的ha.handle方法实际上是调用了
RequestMappingHandlerAdapter.
handleInternal
有了以上⑥的结论以后,我们继续追踪ModelAndView的源头,从
RequestMappingHandlerAdapter.
handleInternal
RequestMappingHandlerAdapter
.invokeHandleMethod,我们来看一看
invokeHandleMethod
的源代码:
【代码片段2】:
* Invoke the RequestMapping handler method preparing a ModelAndView if view resolution is required.
4 private ModelAndView invokeHandleMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//step 1、ModelAndView的前世:是一个ModelAndViewContainer实例
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
* RequestContextUtils.getInputFlashMap(request)可以获取到request中的attribute,
* 并且将所有的request中的attribute放置在mavContainer中,此时使用的是defaultModel
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
* 在RequestMappingHandlerAdapter中ignoreDefaultModelOnRedirect默认为false
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
//省略许多代码...
if (asyncManager.hasConcurrentResult()) {
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
//step 2、调用handler方法,
requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
//省略许多代码...
//step 3、从mavContainer中获取到ModelAndView实例,返回
return getModelAndView(mavContainer, modelFactory, webRequest);
【代码片段2】
ModelAndViewContainer是个什么东西?同样从
中我们可以得出如下的结论:
ModelMap实际上就是一个LinkedHashMap
&String, Object&
,可以用于存放key-value的集合;
ModelAndViewContainer含有两个ModelMap对象
defaultModel和redirectModel,默认情况下使用defaultModel
有了以上两个结论,我们还有必要分析一下ModelAndViewContainer的一些细节(主要参看下面代码中的注释):
【代码片段3】:
1 public class ModelAndViewContainer {
* 对这7个属性我们可以将其分为3个部分来看
// 1、两个模型和一个view,其中view可以存放任何java类型
// * 注意这个是final类型,也就是不能再重新为defaultModel赋值
private final ModelMap defaultModel = new BindingAwareModelMap();
private ModelMap redirectM
// 2、记录当前的Model使用策略
private boolean ignoreDefaultModelOnRedirect =
private boolean redirectModelScenario =
// 3、记录request和session的处理状态
private final SessionStatus sessionStatus = new SimpleSessionStatus();
private boolean requestHandled =
//和view属性相关的处理方法
* 对view的处理主要分为String类型和非String类型。如果views是一个
* String类型的对象,那么它就是下面说的isViewReference
public void setViewName(String viewName) {
this.view = viewN
public String getViewName() {
return (this.view instanceof String ? (String) this.view : null);
public void setView(Object view) {
this.view =
public Object getView() {
return this.
* 注意,如果veiw是一个String类型,那么isViewReference
public boolean isViewReference() {
return (this.view instanceof String);
//和model相关的处理方法
* 假设redirectModelScenario = R ,ignoreDefaultModelOnRedirect = I ,(redirectModel == null)= M
* 那么(R, I, M)共有8中组合情况,useDefaultModel返回false(也就是使用redirectModel)只有三种情况:
* (1,1,0)、(1,1,1)、(1,0,0)
* a:如果同时设置了redirectModelScenario和ignoreDefaultModelOnRedirect为true,那么无论redirectModel
是否为null,都会使用redirectModel;
* b:如果设置了redirectModelScenario为true,而ignoreDefaultModelOnRedirect为false,同时redirectModel
为null,那么也会使用redirectModel;
private boolean useDefaultModel() {
return (!this.redirectModelScenario || (!this.ignoreDefaultModelOnRedirect
&& this.redirectModel == null));
* 这个方法是重要的,通过设置redirectModelScenario和ignoreDefaultModelOnRedirect来影响该方法的返回值;
* 如果没有初始化redirectModel,那么就会new一个ModelMap对象进行返回;
public ModelMap getModel() {
if (useDefaultModel()) {
return this.defaultM
return (this.redirectModel != null) ? this.redirectModel : new ModelMap();
public ModelMap getDefaultModel() {
return this.defaultM
public void setRedirectModel(ModelMap redirectModel) {
this.redirectModel = redirectM
* Whether the controller has returned a redirect instruction, e.g. a
* &redirect:& prefixed view name, a RedirectView instance, etc.
public void setRedirectModelScenario(boolean redirectModelScenario) {
this.redirectModelScenario = redirectModelS
public void setIgnoreDefaultModelOnRedirect(boolean ignoreDefaultModelOnRedirect) {
this.ignoreDefaultModelOnRedirect = ignoreDefaultModelOnR
//省略一些方法...
接下来分析
【代码片段2】
requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
中对mavContainer做了什么事情?看看
requestMappingMethod.invokeAndHandle(webRequest, mavContainer)
的源代码:
【代码片段4】:
*Invokes the method and handles the return value through one of the configured HandlerMethodReturnValueHandlers.
4 public void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 调用handler方法,的到返回结果为returnValue
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {//handler返回null
if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
}else if (StringUtils.hasText(this.responseReason)) {
mavContainer.setRequestHandled(true);
// 设置标志位,表示当前request请求还没有处理完成
mavContainer.setRequestHandled(false);
// 处理返回结果returnValue
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage(&Error handling return value&, returnValue), ex);
看看上面代码中是如何处理返回结果returnValue的,
.returnValueHandlers.handleReturnValue
实际上调用的是
HandlerMethodReturnValueHandlerComposite
.handleReturnValue方法,代码分析如下:
【代码片段5】:
1 public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//寻找能够处理returnType类型的HandlerMethodReturnValueHandler实例
HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);
//如果没有找到对应的HandlerMethodReturnValueHandler,则会返回一个异常
Assert.notNull(handler, &Unknown return value type [& + returnType.getParameterType().getName() + &]&);
//用上面寻找到的handler来处理返回结果
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
从上面的代码看出,处理返回结果分为两个步骤:①、寻找能够处理
returnType
类型的HandlerMethodReturnValueHandler,如果没有找到,则会抛出异常;②、利用已经找到的handler来处理返回结果;
同时,我们要注意HandlerMethodReturnValueHandler是一个接口类型,该接口只有两个方法:boolean supportsReturnType(MethodParameter returnType)和void handleReturnValue(...)。看看它有多少个实现类:
既然是这样,我们就像看看到底是如何确定处理返回结果的handler的呢??同时,又能够处理多少种不同的handler返回类型呢??
getReturnValueHandler(returnType)
方法的源代码:
【代码片段6】:
* Find a registered HandlerMethodReturnValueHandler that supports the given return type
4 private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
* returnValueHandlers是List&HandlerMethodReturnValueHandler&类型,
* 在调试的时候可以看到它共包含了13个对象。还可以增减吗??如何注
* 册一个returnValueHandler呢??有待探究。
for (HandlerMethodReturnValueHandler returnValueHandler : returnValueHandlers) {
if (logger.isTraceEnabled()) {
logger.trace(&Testing if return value handler [& + returnValueHandler + &] supports [& +
returnType.getGenericParameterType() + &]&);
if (returnValueHandler.supportsReturnType(returnType)) {
return returnValueH
我们可以看到,在
getReturnValueHandler
方法中会遍历
returnValueHandlers
(实际上是一个
List&HandlerMethodReturnValueHandler&
类型),如果遇到能够支持返回值类型的handler,则将其返回。在调试中看看
returnValueHandlers
链表中都有哪些对象:
可以看见,
returnValueHandlers
链表中一共有14个对象,对应于上面说的HandlerMethodReturnValueHandler接口实现类中除了
HandlerMethodReturnValueHandlerComposite
类之外的其它实现类对象。这个有点儿意思哈(^_^)。
如果在request请求处理的handler方法中返回String类型,则其
getReturnValueHandler(returnType)
方法就会返回一个ViewNameMethodReturnValueHandler类型的实例。看看ViewNameMethodReturnValueHandler类的定义:
【代码片段7】:
1 public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
private String[] redirectP
public void setRedirectPatterns(String... redirectPatterns) {
this.redirectPatterns = redirectP
public String[] getRedirectPatterns() {
return this.redirectP
public boolean supportsReturnType(MethodParameter returnType) {
Class&?& paramType = returnType.getParameterType();
return (void.class.equals(paramType) || String.class.equals(paramType));
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue == null) {
else if (returnValue instanceof String) {
String viewName = (String) returnV
// 对mavContainer的设置就是将view属性赋值为returnValue
mavContainer.setViewName(viewName);
/* 如果returnValue指示为redirect(比如说&redirect:&前缀,redirect pattern的设置等)
* 则将设置redirectModelScenario为true。
if (isRedirectViewName(viewName)) {
mavContainer.setRedirectModelScenario(true);
// should not happen
throw new UnsupportedOperationException(&Unexpected return type: & +
returnType.getParameterType().getName() + & in method: & + returnType.getMethod());
* Whether the given view name is a redirect view reference.
* The default implementation checks the configured redirect patterns and
* also if the view name starts with the &redirect:& prefix.
* @param viewName the view name to check, never {@code null}
* @return &true& if the given view name is recognized as a redirect view
* &false& otherwise.
protected boolean isRedirectViewName(String viewName) {
if (PatternMatchUtils.simpleMatch(this.redirectPatterns, viewName)) {
return viewName.startsWith(&redirect:&);
到现在为止,request请求的handler方法也调用了。同时根据handler方法的返回结果调用不同的Xxx
ReturnValueHandler的
handleReturnValue
方法对mavContainer的view及其状态进行了设置。
我们分析出:
如果handler方法的返回类型是String的话
①设置mavContainer的Object view为该返回字符串;②如果返回字符串中以“redirect:”开头,则设置redirectModelScenario为true
(也可以通过redirect pattern来设置,这种方式目前还不熟悉??)。
接下来就是通过设置好的
mavContainer
来得到一个ModelAndView。
【代码片段2】
具体就是执行
getModelAndView(mavContainer, modelFactory, webRequest) 返回一个ModelAndView,成功的将handler的各种类型的返回结果转换成ModelAndView。
getModelAndView
源代码,分析其流程,我们可以再反过来推step2中还需要做哪些设置:
【代码片段8】:
1 private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
//得到defaultModel或者是redirectModel
ModelMap model = mavContainer.getModel();
* 注意mavContainer.getViewName()方法,如果mavContainer的Object view是一个String类型,
* 则返回该字符串;如果不是,则得到null
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
if (model instanceof RedirectAttributes) {
Map&String, ?& flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致2013年3月 总版技术专家分月排行榜第二
2014年2月 Java大版内专家分月排行榜第一2013年8月 Java大版内专家分月排行榜第一2013年5月 Java大版内专家分月排行榜第一2013年4月 Java大版内专家分月排行榜第一2013年3月 Java大版内专家分月排行榜第一2013年2月 Java大版内专家分月排行榜第一
本帖子已过去太久远了,不再提供回复功能。Spring技术内幕——深入解析Spring架构与设计原理(四)Web MVC的实现 - jiwenke - ITeye技术网站
博客分类:
以前的欠账,现在补上,欢迎指正和讨论。
Spring Web MVC的实现
关于MVC,这是和WEB开发相关的部分,显然大家都是很熟悉了。从最初的JSP到struts,再到像wicket等等,真是百花齐放,百家争鸣.在WEB UI上,这部分是做web应用架构选择不可缺少的一部分。而作为MVC框架,也许SPRING MVC不能算得上是表现力最出色的UI框架,但无疑,它的实现也是非常的优秀,同时,我们可以从它的实现上,看到一个非常清晰的MVC实现的过程,从这点上看,真是非常的过瘾啊!
在了解IOC容器的基本实现的基础上,下面我们来看看,在典型的Web环境中,Spring IOC容器是如何在Web环境中被载入并起作用的。我们可以看到,对于MVC这部分,主要建立在IOC的基础上,AOP的特性应用得并不多。Spring并不是天生就能在Web容器中起作用的,同样也需要一个启动过程,把自己的IOC容器导入,并在Web容器中建立起来。
与对IoC容器的初始化的分析一样,我们同样看到了loadBeanDefinition对BeanDefinition的载入。在Web环境中,对定位BeanDefinition的Resource有特别的要求,对这个要求的处理体现在getDefaultConfigLocations方法的处理中。可以看到,在这里,使用了默认的BeanDefinition的配置路径,这个路径在XmlWebApplicationContext中,已经作为一个常量定义好了,这个常量就是/WEB-INF/applicationContext.xml。这里的loadBeanDefinition实现如下所示:
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
/** Default config location for the root context */
//这里是设置缺省BeanDefinition的地方,在/WEB-INF/applicationContext.xml文件里,如果不特殊指定其他文件,IoC容器会从这里读取BeanDefinition来初始化IoC容器
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
/** Default prefix for building a config location for a namespace */
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
/** Default suffix for building a config location for a namespace */
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
//我们又看到了熟悉的loadBeanDefinition,就像我们前面对IOC容器的分析一样,这个加载过程在容器refresh()时启动。
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
// 对于XmlWebApplicationContext,当然是使用XmlBeanDefinitionReader来对BeanDefinition信息进行解析
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
// 这里设置ResourceLoader,因为XmlWebApplicationContext是DefaultResource的子类,所以这里同样会使用DefaultResourceLoader来定位BeanDefinition
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
//这里使用定义好的XmlBeanDefinitionReader来载入BeanDefinition
loadBeanDefinitions(beanDefinitionReader);
protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {
//如果有多个BeanDefinition的文件定义,需要逐个载入,都是通过reader来完成的,这个初始化过程是由refreshBeanFactory方法来完成的,这里只是负责载入BeanDefinition
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
reader.loadBeanDefinitions(configLocation);
进入DispatcherServlet和MVC实现
完成了在Web环境中,IoC容器的建立以后,也就是在完成对ContextLoaderListener的初始化以后,Web容器开始初始化DispatcherServlet,接着,会执行DispatcherServlet持有的IoC容器的初始化过程,在这个初始化过程中,一个新的上下文被建立起来,这个DispatcherServlet持有的上下文,被设置为根上下文的子上下文。可以大致认为,根上下文是和Web应用相对应的一个上下文,而DispatcherServlet持有的上下文是和Servlet对应的一个上下文,在一个Web应用中,往往可以容纳多个Servlet存在;与此相对应,对于应用在Web容器中的上下体系,也是很类似的,一个根上下文可以作为许多Servlet上下文的双亲上下文。在DispatcherServlet,我们可以看到对MVC的初始化,是在DispatcherServlet的initStrategies完成的。
在这个初始化完成以后,会在上下文中建立器一个执行器于url的对应关系,这个对应关系可以让在url请求到来的时候,MVC可以检索到相应的控制器来进行处理,如以下代码所示:
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
//这里从request中得到请求的url路径
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
//这里使用得到的url路径对Handler进行匹配,得到对应的Handler,如果没有对应的Hanlder,返回null,这样默认的Handler会被使用
Object handler = lookupHandler(lookupPath, request);
if (handler == null) {
// We need to care for the default handler directly, since we need to
// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
Object rawHandler =
if ("/".equals(lookupPath)) {
rawHandler = getRootHandler();
if (rawHandler == null) {
rawHandler = getDefaultHandler();
if (rawHandler != null) {
validateHandler(rawHandler, request);
handler = buildPathExposingHandler(rawHandler, lookupPath, null);
if (handler != null && logger.isDebugEnabled()) {
logger.debug("Mapping [" + lookupPath + "] to handler '" + handler + "'");
else if (handler == null && logger.isTraceEnabled()) {
logger.trace("No handler mapping found for [" + lookupPath + "]");
// lookupHandler是根据url路径,启动在handlerMap中对handler的检索,并最终返回handler对象
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
// Direct match?
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
validateHandler(handler, request);
return buildPathExposingHandler(handler, urlPath, null);
// Pattern match?
String bestPathMatch =
for (String registeredPath : this.handlerMap.keySet()) {
if (getPathMatcher().match(registeredPath, urlPath) &&
(bestPathMatch == null || bestPathMatch.length() & registeredPath.length())) {
bestPathMatch = registeredP
if (bestPathMatch != null) {
handler = this.handlerMap.get(bestPathMatch);
validateHandler(handler, request);
String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPathMatch, urlPath);
Map&String, String& uriTemplateVariables =
getPathMatcher().extractUriTemplateVariables(bestPathMatch, urlPath);
return buildPathExposingHandler(handler, pathWithinMapping, uriTemplateVariables);
// No handler found...
最后,我们可以结合在DispatcherServlet中,对请求的分发处理来了解一个url请求到来时,MVC的实现和协同处理过程,如以下代码所示:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest =
HandlerExecutionChain mappedHandler =
int interceptorIndex = -1;
//这里为视图准备好一个ModelAndView,这个ModelAndView持有handler处理请求的结果
ModelAndView mv =
boolean errorView =
processedRequest = checkMultipart(request);
// Determine handler for the current request.
// 根据请求得到对应的handler,hander的注册以及getHandler的实现在前面已经分析过
mappedHandler = getHandler(processedRequest, false);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
// Apply preHandle methods of registered interceptors.
// 调用hander的拦截器,从HandlerExecutionChain中取出Interceptor进行前处理
HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
if (interceptors != null) {
for (int i = 0; i & interceptors. i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
interceptorIndex =
// Actually invoke the handler.
// 这里是实际调用handler的地方,在执行handler之前,用HandlerAdapter先检查一下handler的合法性:是不是按Spring的要求编写的handler
// handler处理的结果封装到ModelAndView对象,为视图提供展现数据
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//这里通过调用HandleAdapter的handle方法,实际上触发对Controller的handleRequest方法的调用
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// Do we need view name translation?
if (mv != null && !mv.hasView()) {
mv.setViewName(getDefaultViewName(request));
// Apply postHandle methods of registered interceptors.
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?
// 这里使用视图对ModelAndView数据的展现
if (mv != null && !mv.wasCleared()) {
render(mv, processedRequest, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
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);
catch (Error err) {
ServletException ex = new NestedServletException("Handler processing failed", err);
// Trigger after-completion for thrown exception.
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
// Clean up any resources used by a multipart request.
if (processedRequest != request) {
cleanupMultipart(processedRequest);
通过MVC框架,实际上是DispatcherServlet的协调运作,得到了ModelAndView对象作为数据处理结果,最后,DispatcherServlet把获得的模型数据交给特定的视图对象,从而完成这些数据的视图呈现工作,这个视图呈现由视图对象的render方法来完成,毫无疑问,对应于不同的视图对象,render方法会完成不同的视图呈现处理,从而为用户提供丰富的Web UI表现。关于这些不同的视图展现,还可以看到很多很有参考意义的开源软件的灵活使用,限于篇幅,这里就不详细说了。
对Spring MVC框架的个人理解
对Spring作为应用平台的Web应用开发而言,Spring为它们提供了Spring MVC框架,作为一个像struts这样的Web框架的替代;当然,作为应用平台,Spring并不会强制应用对Web框架的选择。但对Web应用开发而言,选择直接使用Spring MVC,可以给应用开发带来许多便利。因为Spring MVC, 毫无疑问,很好的提供了与Web环境中的IoC容器的集成。同时,和其他Web应用一样,使用Spring MVC, 应用只需要专注于处理逻辑和视图呈现的开发(当然这些开发需要符合Spring MVC的开发习惯),在视图呈现部分,Spring MVC同时也集成了许多现有的Web UI实现,比如像Excel, PDF这些文档视图的生成,因为,集成第三方解决方案,实在可以说是Spring的拿手好戏,从这种一致性的开发模式上看,它在很大程度上降低了Web应用开发的门槛。
浏览 15011
论坛回复 /
(6 / 9018)
引用作为应用平台,Spring并不会强制应用对Web框架的选择。但对Web应用开发而言,选择直接使用Spring MVC,可以给应用开发带来许多便利
支持楼主的看法,SpringMVC确实是个不错的选择,方便实用,而且能够更好的和SpringIOC等功能结合起来使用,只是现在SSH的风吹的太烈的,很多人都有跟风的感觉!
SSH已经是江湖上极为流行的组合了,但由于我个人在WEB UI上涉及较晚,倒是没有受到struts的影响,可以说是对它是一窍不通,我在WEB UI上用的框架是Wicket,当然还有Spring MVC,我感觉都是很好用的一个框架。和Spring的耦合性也不高,我挺喜欢它的,可能是自己见识少,坐井观天的缘故吧。
Wicket的开发和SWING的开发很像,而SPRING MVC因为是SPRING中的一个组件,所以可以说是各有特点。
看了,struts写错了 =。=
太感谢你了!!已经改正了。
作为应用平台,Spring并不会强制应用对Web框架的选择。但对Web应用开发而言,选择直接使用Spring MVC,可以给应用开发带来许多便利
支持楼主的看法,SpringMVC确实是个不错的选择,方便实用,而且能够更好的和SpringIOC等功能结合起来使用,只是现在SSH的风吹的太烈的,很多人都有跟风的感觉!
浏览: 297337 次
来自: 南京
浏览量:111819
浏览量:18787
不知大家有没发现,国产书,国人写的书就没几本是给力的,以后国人 ...
买了这本书,感觉很不值。来吐槽下,也许你自己是专家,不过写的书 ...
作者,写的书很好,我觉得幸亏有源码,所以我才能看懂。一边看,一 ...
说的真不错。。学习了
TransactionProxyFactoryBean 什么情 ...

我要回帖

更多关于 大疆创新股票002168 的文章

 

随机推荐