从源码上理清springmvc用注解方式使用的流程脉络(上)

来源:互联网 发布:手机网络正常微信不能 编辑:程序博客网 时间:2024/06/09 23:06

         作为一款表现层的框架,springmvc没有像struts2那么激进,struts2自己构建一套数据抽象和流程,几乎和servlet环境剥离开。springmvc和servlet可以说是环环紧扣,这也使得springmvc的性能损耗相比struts2来的小,而源码理解门槛相对低,因为理解springmvc可以从servlet的生命周期作为入口。

         在本文中只针对servlet生命周期中的的doService阶段来理清下springmvc使用注解方式的抽象层次流程,以及流程中遇到的核心接口抽象。窃以为,只要读懂了这些重要的接口抽象,进而可以读懂各个具体的组件及整个框架的具体流程细节。读了springmvc的源码为什么会觉得层次清晰简单又功能强大,我想这都是抽象接口的作用。


         要先了解springmvc的接口抽象可先看这篇文章《SpringMVC源码剖析(一)- 从抽象和接口说起》。贴出的源码省略掉了一些无关紧要或者不影响抽象层次流程表达的代码,这也是阅读开源代码的有效方法,集中在当前相关的逻辑,只抓主干,忽略次要,简化细节,这样才能站在更高的层次看清全貌,不致在代码迷雾中首尾失顾。


类DispatcherServlet的方法doService方法中最重要的是调用了:

doDispatch(request, response);

这个方法也是整个springmvc的最重要方法,展现了请求的整个处理流程:

/** * Process the actual dispatching to the handler. * <p>The handler will be obtained by applying the servlet's HandlerMappings in order. * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters * to find the first that supports the handler class. * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers * themselves to decide which methods are acceptable. * @param request current HTTP request * @param response current HTTP response * @throws Exception in case of any kind of processing failure */protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {        HttpServletRequest processedRequest = request;        HandlerExecutionChain mappedHandler = null;ModelAndView mv = null;Exception dispatchException = null;try {// Determine handler for the current request.mappedHandler = getHandler(processedRequest, false);// Determine handler adapter for the current request.HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());                                if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {dispatchException = ex;}processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}

主干的逻辑含义是: 

1.获取处理器执行链(HandlerExecutionChain类包装了真正处理请求的处理对象和一系列的拦截器);

2.获取处理对象对应的适配器,通过处理对象的适配器调用处理方法并返回结果处理的模型视图对象;

3.对模型视图对象进行解析处理返回响应。

补充说明:处理器执行链和struts2的框架设计思路是一致的,在调用真正的处理方法前后,拦截器的相应拦截方法会被执行。下面针对这三方面展开说明:


1.获取处理器执行链

/** * Return the HandlerExecutionChain for this request. * <p>Tries all handler mappings in order. * @param request current HTTP request * @return the HandlerExecutionChain, or <code>null</code> if no handler could be found */protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {for (HandlerMapping hm : this.handlerMappings) {HandlerExecutionChain handler = hm.getHandler(request);if (handler != null) {return handler;}}return null;}

getHandler方法中是通过抽象接口HandlerMapping来获取处理器执行链的,从请求逻辑上来理解,HandlerMapping接口的作用是通过请求过来的url找到相应的处理对象,针对使用注解的方式,处理对象就可简单地理解为Controller的方法,并且方法有配置注解@RequestMapping。在项目启动时对框架进行初始化产生了一系列的HandlerMapping会根据HttpServletRequest对象进行分析决策,轮询找出第一个不为空值的处理器执行链对象。


2.处理对象适配器调用处理方法

获取处理器的适配器就不展开说明,其设计思路可参考之前的博文《springmvc源码心得之handler及handlerAdapter设计》。

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());这句语句内涵十分丰富,许多接口抽象组件在这个代码调用中轮番出现,延伸出了广阔的外延。mvc框架的一系列通用的问题:比如,http请求参数自动映射成java对象(简称jo,包括方法的参数jo);请求参数的类型自动转换成jo的类型;如果对象的类型是复合类型,那么就要使用绑定器来绑定对象的属性;使用mvc框架的用户在请求逻辑处理后是返回视图还是某种结构的数据,如果是返回数据,响应的数据对象时怎么自动转成json或xml结构的数据,等等。相比Struts2, springmvc的注解配置方式针对这一系列问题的处理方式更为高效简单成熟。  springmvc 的注解方式其实就是一种restful风格的实现,这是一种面向资源,方法级别进行逻辑处理的风格,是一种规约优于配置的好的实现风格。

有点疲倦,暂时搁笔,未完待续。

















1 0
原创粉丝点击