springMVC源码浅析

时间:2023-03-09 19:11:13
springMVC源码浅析

因故,需要学习springmvc,现在demo已经跑起来。列文分析springmvc并简单对比struts2.

springmvc的核心对象dispatcherServlet。struts2的核心对象是strutsPrepareAndExecuteFilter,拦截的方式不同,但同为前段控制器(front controller)设计模式。

springMVC源码浅析

dispatcherServlet的初始化:

JVM加载dispatcherServlet时,会先执行静态代码块:

static{
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}

这两行将springMVC包内的dispatcherServlet.properties文件中缺省的HandlerAdapter、HandlerMapping、ViewResolver等等。

容器初始化时,会调用HttpServlet的init()方法,这个方法被httpServletBean重写了,在httpServletBean中,调用frameworkServlet的initServletBean()方法,这个方法在调用dispatcherServlet真正的onRefresh()方法,到initStrategies()。

initStrategies()有所有的初始化工作:【老版本好像叫做initFrameworkServlet

protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);//初始化所有的请求映射,存储到dispatcherServlet的handlerMappings成员变量中(List)
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);//初始化所有视图解析器,存储到dispatcherServlet的viewResolvers成员变量中(List)
initFlashMapManager(context);
}

dispatcherServlet对请求的拦截:

一个请求到达后端时,若符合我们dispatcherServlet的servletMapping,则会进入dispatcherServlet。默认会调用其父类frameworkServlet的doGet、doPost方法,这两个方法再分发到protected final void processRequest(request,response)方法中。这个方法会调用dispatcherServlet的doService(request,response)方法。

然后在此方法中截取URI,然后把上下文等信息放在request的attribute中,调用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;
mappedHandler = getHandler(processedRequest, false);//拿到HandlerExecutionChain
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());//拿到HandlerExecutionChain中封装的HandlerAdapter
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//执行所有的interceptor的interceptor.preHandle(request, response, this.handler)方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());//执行真handlerAdapter中封装的controller真正的业务方法,返回modelAndView
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
} applyDefaultViewName(request, mv);
//执行所有拦截器的interceptor.postHandle(request, response, this.handler, modelAndView)方法
              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()) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
} //遍历所有注册的handlerMappings,拿出一个支持当前handlerMapping的adapter,封装到HandlerExecutionChain中
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
HandlerExecutionChain handler = hm.getHandler(request);//不同类型的handlerMapping有不同的getHandler实现
if (handler != null) {
return handler;
}
}
return null;
}

doDispatch业务处理方法:
1、通过URI,遍历成员变量handlerMappings,拿到URI对应的controller、interceptor放到HandlerExecutionChain中(不同类型的mapping拿的方式不一样,如SimpleUrlHandlerMapping是通过URI映射规则从map中拿到controller)。

从doDispatcher的代码中,很明显可以看出一条线索,整个方法是围绕着如何获取HandlerExecutionChain对象,执行HandlerExecutionChain对象得到相应的视图对象,再对视图进行渲染这条主线来展开的。HandlerExecutionChain对象显得异常重要。

因为Http请求要进入SpringMVC的处理体系,必须由HandlerMapping接口的实现类映射Http请求,得到一个封装后的HandlerExecutionChain对象。再由HandlerAdapter接口的实现类来处理这个HandlerExecutionChain对象所包装的处理对象,来得到最后渲染的视图对象。

2、循环所有的HandlerAdapter,通过support方法拿到支持目标controller的的一个adapter。

springMVC源码浅析

循环所有已注册的HandlerAdapter(处理器适配器),如果该适配器支持ha.supports(handler)当前处理器,就返回。由此可见,Spring通过HandlerAdapter使处理器解耦,实处理器(Handler)不只是仅仅局限于控制器(Controller)这一种形式。目前Spring可以支持,ServletHttpRequestHandlerThrowawayControllerController,从这一点上看Spring已为客户留出了很大空间作为扩展的口子。

http://www.blogjava.net/hao-zhang-hi/archive/2011/03/10/346081.html

3、调用adapter 的applyPreHandle(request,response),执行所有的interceptor的interceptor.preHandle(request, response, this.handler)方法。

4、调用adapter的handle(request, response, mappedHandler.getHandler());去执行controller中真正的业务方法,返回ModelAndView对象。

5、调用adapter的applyPostHandle(request,response,modelAndView)方法,执行所有拦截器的interceptor.postHandle(request, response, this.handler, modelAndView)方法。

6、调用processDispatchResult(request,response,HandlerExecutionChain,ModelAndView,Exception),如果exception不为空,返回配置的异常modelAndView。如果exception为空,根据modelAndView中的字符串拼接视图完整路径。

7、如我们配置了jsp的JstlView,调用view.render(Map model,request,response),调用InternalResourceView的renderMergedOutputModel方法,拿到requestDispatcher,forward到视图。最后执行mappedHandler.triggerAfterCompletion(request, response, null)

springMVC源码浅析

Spring MVC PK Struts2

我们用struts2时采用的传统的配置文件的方式,并没有使用传说中的0配置。spring3 mvc可以认为已经100%零配置了(除了配置spring mvc-servlet.xml外)。

Spring MVC和Struts2的区别:

1. 机制:spring mvc的入口是servlet,而struts2是filter(这里要指出,filter和servlet是不同的。以前认为filter是servlet的一种特殊),这样就导致了二者的机制不同,这里就牵涉到servlet和filter的区别了。

(区别:1,servlet 流程是短的,url传来之后,就对其进行处理,之后返回或转向到某一自己指定的页面。它主要用来在
     业务处理之前进行控制.
  2,filter 流程是线性的, url传来之后,检查之后,可保持原来的流程继续向下执行,被下一个filter, servlet接收等,而servlet 处理之后,不会继续向下传递。filter功能可用来保持流程继续按照原来的方式进行下去,或者主导流程,而servlet的功能主要用来主导流程。
     filter可用来进行字符编码的过滤,检测用户是否登陆的过滤,禁止页面缓存等
3, servlet,filter都是针对url之类的,而listener是针对对象的操作的,如session的创建,session.setAttribute的发生,在这样的事件发生时做一些事情。
     可用来进行:Spring整合Struts,为Struts的action注入属性,web应用定时任务的实现,在线人数的统计等

4,interceptor 拦截器,类似于filter,不过在struts.xml中配置,不是在web.xml,并且不是针对URL的,而是针对action,当页面提交action时,进行过滤操作,相当于struts1.x提供的plug-in机制,可以看作,前者是struts1.x自带的filter,而interceptor 是struts2 提供的filter.
    与filter不同点:(1)不在web.xml中配置,而是在struts.xml中完成配置,与action在一起
                            ( 2  ) 可由action自己指定用哪个interceptor 来在接收之前做事)

2. 性能:spring会稍微比struts快。spring mvc是基于方法的设计,而sturts是基于类,每次发一次请求都会实例一个action,每个action都会被注入属性,而spring基于方法,粒度更细,但要小心把握像在servlet控制数据一样。spring3 mvc是方法级别的拦截,拦截到方法后根据参数上的注解,把request数据注入进去,在spring3 mvc中,一个方法对应一个request上下文。而struts2框架是类级别的拦截,每次来了请求就创建一个Action,然后调用setter getter方法把request中的数据注入;struts2实际上是通过setter getter方法与request打交道的;struts2中,一个Action对象对应一个request上下文。

3. 参数传递:struts是在接受参数的时候,可以用属性来接受参数,这就说明参数是让多个方法共享的。

4. 设计思想上:struts更加符合oop的编程思想, spring就比较谨慎,在servlet上扩展。

5. intercepter的实现机制:struts有以自己的interceptor机制,spring mvc用的是独立的AOP方式。这样导致struts的配置文件量还是比spring mvc大,虽然struts的配置能继承,所以我觉得论使用上来讲,spring mvc使用更加简洁,开发效率Spring MVC确实比struts2高。spring mvc是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上spring3 mvc就容易实现restful url。struts2是类级别的拦截,一个类对应一个request上下文;实现restful url要费劲,因为struts2 action的一个方法可以对应一个url;而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了。spring3 mvc的方法之间基本上独立的,独享request response数据,请求数据通过参数获取,处理结果通过ModelMap交回给框架方法之间不共享变量,而struts2搞的就比较乱,虽然方法之间也是独立的,但其所有Action变量是共享的,这不会影响程序运行,却给我们编码,读程序时带来麻烦。

6. 另外,spring3 mvc的验证也是一个亮点,支持JSR303,处理ajax的请求更是方便,只需一个注解@ResponseBody ,然后直接返回响应文本即可。送上一段代码:

@RequestMapping(value="/whitelists") public String index(ModelMap map) { Account account = accountManager.getByDigitId(SecurityContextHolder.get().getDigitId()); List<Group> groupList = groupManager.findAllGroup(account.getId()); map.put("account", account); map.put("groupList", groupList); return "/group/group-index"; }
// @ResponseBody ajax响应,处理Ajax请求也很方便 @RequestMapping(value="/whitelist/{whiteListId}/del") @ResponseBody public String delete(@PathVariable Integer whiteListId) { whiteListManager.deleteWhiteList(whiteListId); return "success"; }

http://www.cnblogs.com/youngdream-ppj/archive/2013/03/20/2971873.html