SpringMVC+Spring阅读笔记——发展历程

来源:互联网 发布:淘宝官方投诉电话号码 编辑:程序博客网 时间:2024/06/11 09:39

http://downpour.iteye.com/blog/1330537#comments

在我们熟知的建立在三层结构(表示层、业务逻辑层、持久层)基础之上的J2EE应用程序开发之中,表示层的解决方案最多。因为在表示层自身的知识触角很多,需要解决的问题也不少,这也就难免造成与之对应的解决方案层出不穷。 


【MVC模型】 

在MVC模型中,我们选取当前比较热门的两大框架Struts2和SpringMVC作为代码示例。 

首先,我们将用户注册场景中最为核心的“用户类”定义出来: 

Java代码  收藏代码
  1. public class User {  
  2.       
  3.     private String email;  
  4.   
  5.     private String password;  
  6.   
  7.     // 省略了setter和getter方法  
  8. }  


紧接着是一个简单的JSP表单: 

Html代码  收藏代码
  1. <form method="post" action="/register">  
  2. <label>Email:</label><input type="text" name="email" />  
  3. <label>Password:</label><input type="password" name="password" />  
  4. <input type="submit" value="submit" />  
  5. </form>  


上述这两段代码无论是SpringMVC还是Struts2,都可以共用。而在请求响应处理类(也就是Controller)上的设计差异是两个框架最大的不同。 

如果使用SpringMVC,那么Controller的代码看上去就像这样: 

Java代码  收藏代码
  1. @Controller  
  2. @RequestMapping  
  3. public class UserController {  
  4.       
  5.     @RequestMapping("/register")  
  6.     public ModelAndView register(String email, String password) {  
  7.         // 在这里调用具体的业务逻辑代码  
  8.         return new ModelAndView("register-success");  
  9.     }  
  10.   
  11. }  


如果使用Struts2,那么Controller的代码看上去就稍有不同: 

Java代码  收藏代码
  1. public class UserController {  
  2.       
  3.     private String email;  
  4.   
  5.     private String password;  
  6.       
  7.     public String register() {  
  8.         // 在这里调用具体的业务逻辑代码  
  9.         return "register-success";  
  10.     }  
  11.        
  12.     // 这里省略了setter和getter方法  
  13.   
  14. }  


除此之外,Struts2还需要在某个配置文件中进行请求映射的配置: 

Xml代码  收藏代码
  1. <action name="register" class="com.demo2do.sandbox.web.UserController" method="register">  
  2.     <result name="success">/register-success.jsp</result>  
  3. </action>  


从上面的代码示例中,我们可以为整个MVC模型的实现总结归纳出一些特点: 

1. 框架本身并不通过某种手段来干预或者控制浏览器发送Http请求的行为方式。 

从上面的代码中我们就可以看到,无论是SpringMVC还是Struts2,它们在请求页面的实现中都使用了原生HTML代码。就算是Http请求的发送,也借助于HTML之中对Form提交请求的支持。 

2. 页面(View层)和请求处理类(Controller)之间的映射关系通过某一种配置形式维系起来。 

我们可以看到在浏览器和Web服务器之间的映射关系在不同的框架中被赋予了不同的表现形式:在SpringMVC中,使用了Annotation注解;在Struts2中,默认采取XML配置文件。不过无论是哪一种配置形式,隐藏在其背后的都是对于请求映射关系的定义。 

3. Controller层的设计差异是不同MVC框架之间最主要的差异。 

这一点实际上是我们在对于MVC模型自身进行定义时就反复强调的一点。在上面的例子中,我们可以看到SpringMVC使用方法参数来对请求的数据进行映射;而Struts2使用Controller类内部的属性来进行数据请求的映射。 

在MVC模型中,浏览器端和服务器端的交互关系非常明确:无论采取什么样的框架,总是以一个明确的URL作为中心,辅之以参数请求。因此,URL看上去就像是一个明文的契约,当然,真正蕴藏在背后的是Http协议。所有的这些东西都被放在了台面上,我们可以非常明确地获取到一次交互中所有的Http信息。这也是MVC模型中最为突出的一个特点。 


【struts2和springmvc简单对比】 

1、springmvc基于方法开发的,struts2基于类开发的。

2、单例和多例的区别:springmvc在映射的时候,通过形参来接收参数的,是将url和controller方法映射,映射成功后,springmvc生成一个handlers对象,对象中只包括一个method,方法执行结束的时候,形参的数据就销毁,

所以springmvc可以进行单例开发,并且建议使用。所以springmvc开发类似于service开发。

但是structs接收的参数是通过类的成员变量来接收的,这些变量在多线程访问中,是共享的,而不是像springmvc那样,方法结束之后,形参自动销毁,且无法使用单例,只能使用多例。

这样的话,在structs中,随着方法的添加,很多的成员变量,维护到最后的时候根本就不知道这个成员变量被哪个方式所使用。struts2一般开发规范是action类(对应Controller)设置为多例,用于处理前后台之间传输的数据。


【Servlet】 

Servlet规范是最基本的J2EE规范,也是我们进行Web开发的核心依赖。它虽然自身并不构成开发框架,但是我们不得不承认所有的MVC框架都是从最基本的Servlet规范发展而来。因此,我们可以得出一个基本结论: 


在Servlet规范中所定义的请求处理响应接口是这样的: 

 

我们可以看到,Servlet的基本接口定义中: 

参数列表 —— Http请求被封装为一个HttpServletRequest对象(或者ServletRequest对象),而Http响应封装为一个HttpServletResponse对象(或者ServletResponse对象) 
返回值 —— 方法不存在返回值(返回值为void)
 

在这个设计中,HttpServletRequest和HttpServletResponse承担了完整的处理Http请求的任务。而这两个Servlet对象的职责也有所分工: 

HttpServletRequest对象 —— 主要用于处理整个Http生命周期中的数据。 
HttpServletResponse对象 —— 主要用于处理Http的响应结果。
 

这里实际上有一点“数据与行为分离”的意味。也就是说,在Servlet处理请求的过程中,其实也是Servlet中响应方法内部的逻辑执行过程中,如果需要处理请求数据或者返回数据,那么我们需要和HttpServletRequest打交道;如果需要处理执行完毕之后的响应结果,那么我们需要和HttpServletResponse打交道。 

这样的设计方式,是一种骨架式的设计方式。因为Servlet是我们进行Web开发中最底层的标准,所以我们可以看到接口设计中的返回值对于一个最底层标准而言毫无意义。因为不存在一个更底层的处理程序会对返回值进行进一步的处理,我们不得不在Servlet的过程中自行处理浏览器的行为控制。 

MVC模型的这一种形态,被笔者冠以一个名称:参数-参数(Param-Param)实现模式。因为在响应方法中,数据与行为的操作载体都以参数的形式出现。 

Servlet的设计模型是所有MVC模型表现形态中最为基础也是最为底层的一种模型,所有其他模型都是建立在这一模型的基础之上扩展而来。 


【Webwork2 / Struts2】 

随着时间的推进,越来越多的程序员在使用Struts1.X进行开发的过程中发现Struts1.X在设计上存在的一些不足。而与此同时,各种各样的Web层的解决方案也如雨后春笋般涌现出来。不仅仅是以MVC模型为基础的开发框架,还有包括JSF和Tapestry之类的基于组件模型的开发框架也在这个时期诞生并不断发展壮大。因此,这个时期应该是整个Web层解决方案的大力发展时期。 

而在这些框架中,有一个来自于Opensymphony开源社区的优秀框架Webwork2探索了一条与传统Servlet模型不同的解决方案,逐渐被大家熟识和理解,不断发展并得到了广大程序员的认可。2004年,Webwork2.1.7版本发布,成为Webwork2的一个重要里程碑,它以优秀的设计思想和灵活的实现,吸引了大批的Web层开发人员投入它的怀抱。 

或许是看到了Struts1.X发展上的局限性,Apache社区与Opensymphony开源组织在2005年底宣布未来的Struts项目将与Webwork2项目合并,并联合推出Struts2,通过Apache社区的人气优势与OpenSymphony的技术优势,共同打造下一代的Web层开发框架。这也就是Struts2的由来。 

从整个过程中,我们可以发现,Webwork2和Struts2是一脉相承的Web层解决方案。而两者能够在一个相当长的时间段内占据开发市场主导地位的重要原因在于其技术上的领先优势。而这一技术上的领先优势,突出表现为对Controller的彻底改造: 

Java代码  收藏代码
  1. public class UserController {  
  2.   
  3.     private User user  
  4.   
  5.     public String execute() {  
  6.         // 这里加入业务逻辑代码  
  7.         return "success";  
  8.     }  
  9.   
  10.     // 这里省略了setter和getter方法  
  11. }  


从上面的代码中,我们可以看到Webwork2 / Struts2对于Controller最大的改造有两点: 

  • 在Controller中彻底杜绝引入HttpServletRequest或者HttpServletResponse这样的原生Servlet对象。
  • 将请求参数和响应数据都从响应方法中剥离到了Controller中的属性变量。
这两大改造被看作是框架的神来之笔。因为通过这一改造,整个Controller类彻底与Web容器解耦,可以方便地进行单元测试。而摆脱了Servlet束缚的Controller,也为整个编程模型赋予了全新的定义。 

当然,这种改造的前提条件在于Webwork2 / Struts2引入了另外一个重要的编程概念:ThreadLocal模式。使得Controller成为一个线程安全的对象被Servlet模型所调用,这也就突破了传统Servlet体系下,Servlet对象并非一个线程安全的对象的限制条件。 


从引入新的编程元素的角度来说,Webwork2 / Struts2无疑也是成功的。因为在传统Servlet模式中的禁地Controller中的属性变量被合理利用了起来作为请求处理过程中的数据部分。这样的改造不仅使得表达式引擎能够得到最大限度的发挥,同时使得整个Controller看起来更像是一个POJO。因而,这种表现形态被笔者冠以的名称是:POJO实现模式。 

POJO实现模式是一种具有革命性意义的模式,因为它能够把解耦合这样一个观点发挥到极致。从面向对象的角度来看,POJO模式无疑也是所有程序员所追求的一个目标。这也就是Webwork2 / Struts2那么多年来经久不衰的一个重要原因。 


【SpringMVC】 

相比较Webwork2 / Struts2,SpringMVC走了一条比较温和的改良路线。因为SpringMVC自始至终都没有突破传统Servlet编程模型的限制,而是在这过程中不断改良,不断重构,反而在发展中开拓了一条崭新的道路。 

我们可以看看目前最新版本的SpringMVC中对于Controller的定义: 

Java代码  收藏代码
  1. @Controller  
  2. @RequestMapping  
  3. public class UserController {  
  4.       
  5.     @RequestMapping("/register")  
  6.     public ModelAndView register(String email, String password) {  
  7.         // 在这里调用具体的业务逻辑代码  
  8.         return new ModelAndView("register-success");  
  9.     }  
  10.   
  11. }  


我们在这里引用了在之前的讲解中曾经使用过的代码片段。不过这一代码片段刚刚好可以说明SpringMVC在整个Controller改造中所涉及到的一些要点: 

1. 使用参数-返回值(Param-Return)实现模式来打造Controller 

方法的参数(email和password)被视作是Http请求参数的概括。而在这里,它们已经被SpringMVC的框架有效处理并屏蔽了内在的处理细节,呈现出来的是与请求参数名称一一对应的参数列表。而返回值ModelAndView则表示Http的响应是一个数据与视图的结合体,表示Http的处理结果。 

2. 引入Annotation来完成请求-响应的映射关系 

引入Annotation来完成请求-响应的映射关系,是SpringMVC的一个重大改造。在早期的SpringMVC以及其他的MVC框架中,通常都是使用XML作为基础配置的。而Annotation的引入将原本分散的关注点合并到了一起,为实现配置简化打下了坚实的基础。 

3. 泛化参数和返回值的含义 

这是一个蕴含的特点。事实上,SpringMVC在响应方法上,可以支持多种多样不同的参数类型和返回值类型。例如,当参数类型为Model时,SpringMVC将会自动将请求参数封装于Model内部而传入请求方法;当返回值类型是String时,直接表示SpringMVC需要返回的视图类型和视图内容。当然,这些泛化的参数和返回值的内容全部都由SpringMVC在框架内部处理了。 

如果我们来评述一下这些特点就会发现,SpringMVC虽然是一个温和的改良派,却是在改良这个领域做得最为出色的。以引入Annotation为例,引入Annotation来完成请求-响应映射,不正是我们反复强调的引入并合理使用新的编程元素来完成处理任务嘛?而泛化后的参数和返回值,则可以让程序员在写Controller的代码时可以随心所欲,不再受到任何契约的束缚,这样一来接口的逻辑语义也就能够更加清晰。 




0 0
原创粉丝点击