Spring的Control设计。

SpringMVC的Control主要由HandlerMapping和HadnlerAdapters两个组件提供。HandlerMapping负责映射用户的URL和对应的处理类,HandlerMapping并没有规定这个URL与应用的处理类如何映射,在HandlerMapping接口中只定义了根据一个URL必须返回一个由HandlerExecutionChain代表的处理链,我们可以在这个处理链中添加任意的HandlerAdapters实例来处理这个URL对应的请求,这种设计思路和在Servlet规范中的Filter处理是类似的。

HandlerMapping初始化

SpringMVC本身也提供了很多HandlerMapping的实现,默认使用的是BeanNameUrlHandlerMapping,可以根据Bean的name属性映射到URL中,如我们定义这样一个Bean:

<alias name="/demo" alias="/demo1" />
<alias name="/demo" alias="/dem2" />
<bean id="demo" name="/demo" class="com.xxx.mvc.Demo">
    <property name="viewPage">
        <value>/demo.htm</value>
    </property>
</bean>

如果没有定义其他HandlerMapping,SpringMVC框架则自动将/demo.htm映射到com.xxx.mvc.Demo处理类,所有以/demo.htm为alias的Bean都被映射到这个URL中。这个Bean也支持简单的正则匹配的方式,如/demo*会匹配所有以/demo为前缀的URL,这种方式其实与钱买你示例中:

<property name="mappings">
    <props>
        <prop key="demo.htm">demo</prop>
    </props>
</property>

是一样的效果,只是这种方式更容易理解一些。SpringMVC提供的几种HandlerMapping实现类基本上都是基于配置实现方式,也就是URL的所有匹配规则都需要我们在配置文件中定义,这种方式既有优点也有缺点。优点是任何人一看配置文件就知道这个应用的URL映射关系,缺点是如果需要映射的URL很多,会导致配置文件非常庞大,最后URL映射关系会很难管理。

前面介绍了HandlerMapping的作用就是帮助我们管理URL和处理类的映射关系,简单地理解,就是将一个或多个URL映射到一个或多个SpringBean中。下面我们以SimpleUrlHandlerMapping为HandlerMapping的实现类,再仔细看看SpringMVC是如何将请求的URL映射到我们定义的Bean的。

先看看HandlerMapping是如何初始化的。SpringMVC提供了一个HandlerMapping的抽象类AbstractHandlerMapping,AbstractHandlerMapping同时还实现了Ordered接口并继承了WebApplicationObjectSupport类,可以让HandlerMapping通过设置setOrder方法提高优先级,并通过覆盖initApplicationContext方法实现初始化的一些工作。
下图所示是SimpleUrlHandlerMapping类初始化时进行的操作。

HandlerMapping的初始化工作完成的两个最重要的工作就是将URL与Handler的对应关系保存在HandlerMap集合中,并将所有的interceptors对象保存在adaptedInterceptors数组中,等请求到来时执行所有的adaptedInterceptors数组中的interceptor对象。所有的interceptor对象必须实现HandlerInterceptor接口。

HandlerAdapter初始化

HandlerMapping可以完成URL与Handler的映射关系,那么HandlerAdapter就可以帮助自定义各种Handler了。因为SpringMVC首先帮助我们把特别的URL对应到一个Handler,那么这个Handler必定符合某种规则,最常见的办法就是我们的所有handler都继承某个接口,然后SpringMVC自然就调用在这个接口中定义的特殊方法。在早期Struts 1 中就采用这种方式,虽然现在的Struts 2 不用继承特定的接口,但是仍然要采用固定的方法,然后通过反射调用这个固定方法,所以也是换汤不换药,SpringMVC框架也逃不过这种方式,但是SpringMVC提供了另外一种方式,可以不固定这个Handler接口类,也就是我们的URL对应的Handler可以实现多个接口,每个接口可以定义不同的方法。

在SpringMVC中提供了如下三个典型的简单HandlerAdapter实现类。

  •     HttpRequestHandlerAdapter:可以继承HttpRequestHandler接口,所有的Handler可以实现其void handleRequest(HttpServletRequest request, HttpServletResponse response)方法,这个方法没有返回值。
  •     SimpleControllerHandlerAdapter:可以继承Controller接口,所有的Handler可以实现其public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)方法,该方法会返回ModelAndView对象,用于后续的模板渲染。
  •     SimpleServletHandlerAdapter:可以直接继承Servlet接口,可以将一个Servlet作为一个Handler来处理这个请求。

SpringMVC的HandlerAdapter机制可以让Handler的实现更加灵活,不需要和其他框架一样只能和某个Handler接口绑定起来。

HandlerAdapter的初始化没有什么特别之处,只是简单地创建一个HandlerAdapter对象,将这个HandlerAdapter对象保存在DispatcherServlet的handlerAdapters集合中。当SpringMVC将某个URL对应到某个Handler时,在handlerAdapters集合中查询那个handlerAdapter对象supports这个Handler,handlerAdapter对象将会被返回,并调用这个handlerAdapter接口对应的方法。如果这个handlerAdapter对象是SimpleControllerHandlerAdapter,则将调用Controller接口的public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)方法。

如果用户没有自定义HandlerAdapter的实现类,SpringMVC框架将提供默认的4个HandlerAdapter实现类。

Control的调用逻辑

整个SpringMVC的调用是从DispatcherServlet的doService方法开始的,在doService方法中将ApplicationContext、localeResolver、themeResolver等对象添加到request中以便于在后面使用。接着就是调用doDispatch方法,这个方法是主要的处理用户请求的地方。

Control的处理逻辑关键就在DispatcherServlet的handlerMappings集合中根据请求的URL匹配每个HandlerMapping对象中的某个Handler,匹配成功后将会返回这个Handler的处理链HandlerExecutionChain对象,而在这个HandlerExecutionChain对象中将会包含用户自定义的多个HandlerInterceptor对象。在HandlerInterceptor接口中定义的3个方法中,preHandler和postHandler分别在Handler执行前和执行后执行,afterCompletion在View渲染完成、DispatcherServlet返回之前执行。这里需要注意的地方是,当preHandle返回false时,当前的请求将在执行完afterCompletion后直接返回,Handler也将不再执行。

看看HandlerExecutionChain类的getHandler方法你会发现返回的是Object对象,所以在这里Handler对象是没有类型的,Handler的类型是由HandlerAdapter决定的。DispatcherServlet会根据Handler对象在其handlerAdapters集合中匹配哪个HandlerAdapter实例来支持该Handler对象,接下来执行Handler对象的相应方法,如该Handler对象的相应方法返回一个ModelAndView对象,接下来就去执行View渲染。

Control的调用逻辑时序图如下图所示。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值