深入剖析Spring Web源码(八) - 处理器映射,处理器适配器以及处理器的实现 - 基于简单控制器流程的实现

1.1.1.1                   基于简单控制器流程的实现

简单控制器的流程定义了简单的控制器接口 (Controller),在流程的开始,它通常通过 Bean名字 URL处理器映射 (BeanNameUrlHandlerMapping)来获得支持此 HTTP请求的一个控制器实例和支持这个控制器的处理器拦截器 (HandlerInterceptor)。通过简单控制处理适配器 (SimpleControllerHandlerAdapter)传递 HTTP请求到简单的控制器( SimpleFormController)来实现 Spring Web MVC的控制流程。这个流程如下图所示,

 

图表 4 ‑15

 

首先,我们分析派遣器 Servlet是如何通过 Bean名字 URL处理器映射获得处理器执行链,也就是上图中的第一步。

 

Bean名字 URL处理器映射是通过一些列的父类继承最终实现处理器映射接口的。其中不同的父类抽象出一个独立的类级别,一个类级别完成一个最小化而又完善的功能。下图是它的类继承实现的树结构。

 

图表 4 ‑16


上图中灰色类,包括 Web应用程序对象支持类和应用程序对象支持类是 Spring环境项目的实现, Web应用程序对象支持类用来初始化时得到 Web应用程序环境 ,而应用程序对象支持类用来初始化时得到 Servlet环境。这里我们不再剖析他们的实现。

 

抽象处理器映射是这个体系结构中直接实现处理器映射接口的抽象类,这个类继承了 Web应用程序对象支持类,目的是监听 Web应用程序环境初始化事件。在初始化事件中,初始化拦截器,这些拦截器是应用到所有处理器的。如下程序注释,

 

 

当派遣器 Servlet要求处理器映射翻译一个请求到处理器执行链的时候,抽象处理器则映射一个内部的处理器,连同初始化的拦截器一起构成处理器执行链返回。抽象处理器定义映射内部的处理器逻辑作为一个抽象的方法,子类需要实现这个方法来解析处理器。如下程序注释,

 

 

我们看见抽象的处理器映射也实现了 Ordered接口,这个接口是用来在有多个处理器映射可供派遣器 Servlet使用时的优先级。

 

类体系结构中的下一个类是抽象 URL处理器映射,正如我们所愿,抽象 URL处理器映射实现了 getHandlerInternal()方法,在方法实现里通过请求的 URL匹配相应的映射处理器和映射拦截器来返回处理器执行链对象的。

 

那么,这些映射拦截器和映射处理器是如何进行初始化的呢?映射的拦截器是在初始化的时候,通过在 Web应用程序环境中查找得到的。这些映射拦截器必须是 MappedInterceptor的子类,而且注册在 Web应用程序环境中。它也提供了一个方法 registerHandler(),供子类调用注册响应的处理器。如下程序注释,

 

 

我们可以看到这些映射拦截器是在 Web应用程序环境中查找得到的,他们必须实现 MappedInterceptor接口。得到的这些 MappedInterceptor接口保存在 MappedInterceptors集合类中,这个类同时提供了基于 URL路径过滤的功能。如下程序注释,

 

 

抽象 URL处理器映射初始化了拦截器和处理器之后,它将如何实现映射请求到处理器执行链的逻辑呢?正如我们所想,它通过 URL精确匹配或者最佳匹配查找注册的拦截器和处理器,然后构造处理器执行链对象。如下程序注释,

 

 

我们看到,抽象 URL处理器映射是在 Web应用程序环境初始化的时候初始化了拦截器,并且提供了通过 URL对拦截器过滤的功能。同时提供方法注册处理器。现在我们将分析,一个子类应该如何注册处理器。在类的体系结构中的下一个类是抽象探测 URL处理器映射,它探测 Web应用程序环境中的所有 Bean,通过某种规则对 Bean名字进行过滤来决定是否注册这个 Bean作为一个处理器。如下程序所示,

 

 

在上面的实现中,处理器是在应用程序环境中探测得到的。所以,我们称为这个类作为抽象探测 URL处理器映射。但是,在抽象 URL处理器映射中,初始化的实现也自动的在应用程序环境中探测了处理器拦截器的实现,所以,我认为把探测处理器拦截器的实现加入当前这个类中更合理。

 

事实上,映射 Bean的名字到 URL Pattern的实现是非常简单的,子类 Bean URL处理器映射通过查看是否一个 Bean名字或者别名以字符 /开头,如果是以字符 /开头,则认为是一个处理器。如下程序所示,

 

 

流程分析到这里,派遣器 Servlet已经通过处理器映射得到了处理器执行链对象。处理器执行链对象包含着一个以 Object为类型的处理器,和一套应用在处理器上的处理器拦截器。接下来派遣器 Servlet则轮询所有注册的处理器适配器(如图 4-15 第二步),查找是否有一个处理器适配器支持此处理器。 Bean URL处理器映射 (BeanNameUrlHandlerMapping)通常用于映射简单的控制器对象,所以,返回的处理器执行链对象里面通常包含着控制器接口( Controller)的实现类。这个轮询结果将返回简单控制处理适配器 (SimpleControllerHandlerAdapter),并且通过它将 HTTP请求传递给控制器进行处理(如果 4-15 第四步和第五步)。简单的控制处理适配器的实现非常简单,正如它的名字所示,它仅仅是个适配器,请看如下类图,

图表 4 ‑17

 

如下程序注释,

 

 

现在我们理解,一个 HTTP请求经过处理器适配器传递到简单控制器的实现,简单控制器将实现任何必要的业务逻辑,最后返回模型数据和逻辑视图给作为总控制器的派遣器 Servlet。简单控制器接口有许多抽象和具体的实现,每个抽象和具体的实现都能完成一个特定的功能,结构清晰合理,易于扩展,使客户程序能够根据业务逻辑的需要选择不同的类继承处理不同的 HTTP请求。下面我们以简单 Form控制器为例说明它是如何完成对 HTTP请求的处理并且返回模型数据和逻辑视图对象给派遣器 Servlet的。下图是简单 Form控制器的实现流程,

 

图表 4 ‑18

 

从上图我们可以看到,简单 Form控制器是通过 HTTP请求方法来判断执行初始化操作还是业务逻辑操作。如果请求是 HTTP GET方法,说明这次请求是这个模块的第一次加载,那么我们应该显示一个 Form给用户,以至于用户可以填写业务逻辑的输入数据。当用户填写了业务逻辑数据后,提交 Form给此模块,那么用户提交使用的一定是 HTTP POST请求,这个请求包含着此模块业务逻辑的输入数据,所以,简单 Form控制器会绑定这些输入数据到业务逻辑模型对象中,这里称为一个命令 (Command)对象 ,以下分析中的命令对象, Form Backing Bean和业务逻辑模型对象指同一个事物,不再做区分。然后,对命令对象进行校验。如果在绑定或者校验过程中出现任何错误,则导出错误对象到 HTTP请求的属性里,接下来在显示 Form视图的时候,同时显示错误,于是,用户得知哪些输入是不合法的。当用户提交了完整而且有效的输入数据后,简单 Form控制器在绑定和校验后,获得了此模块需要的输入数据后,使用服务层的服务进行业务逻辑的处理,处理后会返回处理结果数据,也就是模型数据,这些模型数据连同成功视图一起返回给作为总控制器的派遣器 Servlet.

 

为了让程序具有可重用性和可扩展性,上面的流程并不是通过一个类实现的。而是通过多个类的继承最终由简单 Form控制器实现的。如下是这些类的实现类图,

 

图表 4 ‑19

 

我们在分析处理器映射的实现中得知上图中被标识为灰色的类和接口是用来对一个对象注入 Web应用程序环境和 Servlet环境的,这里我们不再详述其实现。继承自 Web应用程序对象支持类的第一个类就是 Web内容产生器,这个类用于校验支持的 HTTP方法,也会产生 HTTP缓存头信息等。如下程序注释,

 

 

类层次的下一个类抽象控制器类实现了控制器接口。但是,这个类除了对方法 handleRequest()进行同步没有做任何实现,并且适配到一个抽象方法 handleRequestInternal(),这个方法是由子类来实现的。如下程序所示,

 

 

类实现体系结构中的下一个类基本命令控制器中引入了领域对象模型命令对象 (Command)的概念,它是一个通用的对象类型,用来存储输入的参数信息。并且引入了对这个领域对象模型进行初始化和校验的逻辑,如下程序注释,

 

 

由此可见,基本命令控制器的实现中提供了实用方法创建命令对象,绑定命令对象和校验命令对象。那么,在下一个类层次中,抽象 Form控制器则使用这些方法进行创建命令对象,校验命令对象,进而实现整体的显示 Form,处理 Form和显示成功试图的流程。如下程序注释,

 

 

如此可见,抽象 Form控制器实现了处理一个 Web Form的主要流程。也就是说,在 Form初始化的时候,则显示 Form视图,而在 Form提交的时候,则处理 Form提交,最后显示成功视图。因此,定义了两个抽象的方法, showForm() processFormSubmission()。也正如我们所想,子类通过实现这两个方法来处理不同的流程。在简单 Form控制器的实现中, showForm()简单的显示了配置的 Form视图。而 processFormSubmission()的实现则判断是否有绑定和校验错误,如果有错误,则转发请求到 Form视图,在 Form视图中显示错误并且提示用户重新输入。如果用户输入了正确有效的数据并且提交 Form,简单 Form控制器则使用服务层的服务处理逻辑,并且连同包含处理结果的模型数据和成功视图返回给作为主控制器的派遣器 Servlet。如下程序注释,

 

 

简单 Form控制器是这个实现体系结构中的最后一个类,在使用它之前,需要为它配置 Form视图和成功视图,它就可以开始工作了。但是,一个真正的控制器类应该改写它的 doActionSubmit()方法,从而实现需要的业务逻辑调用。

 

最总我们可以看见,简单 Form 控制器实现并不是单一的类实现,在实现上有很多的层次,每个层次完成一个相对独立的功能,下一层紧紧的依赖于上一层。当你选择实现一个控制器的时候,可以根据需求选择实现哪个层次的抽象类控制器,甚至控制器接口本身。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值