现在的位置: 首页 > 综合 > 正文

Spring MVC framework深入分析之三(下)–执行过程

2016年10月14日 ⁄ 综合 ⁄ 共 3058字 ⁄ 字号 评论关闭

OK.是不是写得很乱?我自己都觉得惭愧啦,没办法,只好让我们再回头分析一下我们碰到几个角色吧:

 

1、HandlerMapping

HandlerMapping这个接口的定义非常简单:

public interface HandlerMapping {

HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

}

不就是根据request的URL path来取得相应的HandlerExecutionChain。

例如:我的URL是 http://localhost:8080/blog/xiecc.htm

RequestURL的字符串一截,拿到了”/xiecc.htm”,再去每个HandlerMapping里一查(还记得初始化时我们已经将所有的HandlerMapping都从配置文件里注入进来了吧),假如我们在某个SimpleUrlHandlerMapping里找到了”/xiecc.htm”,我就立刻可以拿到它对应Controller和一组intercetpors了,拿过来组装一下就是一个HandlerExecutionChain啦。

下面是HandlerMapping的类图:

 

看上去有点麻烦,其实挺简单,具体的类我就不分析啦。它的核心是:it’s all about HashMap。

还记得我们在Spring MVC最常用的HandlerMapping吗?是SimpleUrlHandlerMapping,我们在配置它的时候,最核心的结构就是HashMap,哈哈!东西都在HashMap里,只要通过URL分析找到HashMap的key,比如说”/xiecc.htm”,用个get方法不就啥都取到了。

在Spring的配置文件里我们可以配置多个HandlerMapping,它会一个一个去找到的,直到找到跟URL匹配的那个Controller,要不然就返回null啦。

2、HandlerExecutionChain

我前面说了HandlerExecutionChain就是一个Controller和一组interceptors。这是我们执行一个request最基本的单元啦。

不过现实情况会稍有些出入,HandlerExecutionChain实际上包括的一个Object和一组interceptor。这个Object是Adaptor,它可以是Controller的Adaptor,也可以是其它类的Adaptor。但现实中我们一般用到的都是Controller,因此不详细分析啦,这里用了Adaptor后大大降低了代码的可读性,来换取与Controller非紧耦合的灵活性。至少我现在认为这样做不是太值。

3、Controller

Controller是Spring MVC执行的核心单元,也是程序员需要自完成的重要部分。用过Spring MVC的人应该都对它非常熟悉啦。所以不做太具体的分析。以下是它的类图:

 

看一下类图就知道啦,这又是Template Method的典型应用。Controller最大的优势也正是利用Template Method,把Controller分解成不同功能的子类。想要把request里的东西populate到一个bean里吗?直接继承SimpleFormController就行啦。想要在Controller里写多个方法吗?用MultiActionController。这些Controller设计得面面俱到,但因为Controller的类层次太多,有的人会觉得烦。呵呵,随个人喜好啦。

不过最核心的是不管这些Controller如何千变万化,它们都实现了统一的Controller接口,这使DispatchAction调它时候根据不需要知道Controller的细节,嗯,the power of interface。

Controller里的数据绑定也是一个值得研究的东西,挺好玩的,不过这次没空写啦。

4、interceptor

Interceptor的接口定义如下:

public interface HandlerInterceptor {

boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception;

void postHandle(

HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)

throws Exception;

void afterCompletion(

HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

throws Exception;

}

具体的我就不展开分析啦,我们只要记住interceptor的三个hook point(在AOP里叫join point,哈哈):Controller执行前,Controller执行后,页面显示完成后。

5、ViewResolver

ViewResolver是一个有趣的角色,它本身完成两个功能:一是完成了View与实际页面名称对应关系的配置,二是View的工厂(这可是标准的工厂模式啊,每个ViewResolver负责生产自己的View)。

以下是ViewResolver接口的定义:

public interface ViewResolver {

View resolveViewName(String viewName, Locale locale) throws Exception;

}

用过Spring MVC的人都配置过ViewResolver,因此这里不详细展开。

我将它对属性分成两类:一类是页面文件配置,包括prefix, suffix;另一类是作为view的工厂注入到View里的属性,如ContentType之类的。

以下是ViewResolver的类图:

 

6、View

View是真正负责显示页面的地方。它的接口如下:

public interface View {

void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception;

}

其实这是一个简单任务,给我一个HashMap,再给个页面URI,把这个页面显示出来还不是小Case。不过不同的View显示到页面上的区别还是挺大的,如果是JSP,我只要把HashMap里的东西填到request里,再交给RequestDispatcher来forward一下就行了;如果是Velocity,那就把HashMap里的东西填到Veloticy的Context里,再把模板生成的东西merge到response的writer里就完事了。当然还有pdf或xls的View,我还没空研究它,哪天有兴趣了再看看吧,以下是View的类图:

 

写完这篇文章后,终于明白了什么叫做眼高手低。本来很希望写得抽象些,最后却发现我写的东西跟一般的流水帐式的源码分析其实区别不太大。呜呜,从具体到抽象很难,再把抽象的东西转化成具体更难,但只有经过这样的一层转换,我们的认识才能有很大的提高,我们的水平才能进步。

 

抱歉!评论已关闭.