# Struts 2的起源和背景

**URL:** <https://www.isharkfly.com/t/struts-2/6529>\
**Category:** 程序语言\
**Created:** [June 26, 2011, 12:21pm UTC](https://www.isharkfly.com/t/struts-2/6529 "2011-06-26T12:21:46Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![honeymoose](https://www.isharkfly.com/user_avatar/www.isharkfly.com/honeymoose/32/20796_2.png) [@honeymoose](https://www.isharkfly.com/u/honeymoose)\
**Post date:** [June 26, 2011, 12:21pm UTC](https://www.isharkfly.com/t/struts-2/6529/1 "2011-06-26T12:21:46Z")

</div>

Struts 2以WebWork优秀的设计思想为核心，吸收了Struts 1的部分优点，建立了一个兼容WebWork和Struts 1的MVC框架，Struts 2的目标是希望可以让原来使用Struts 1、WebWork的开发人员，都可以平稳过渡到使用Struts 2框架。

Struts 1简介及存在的问题

从过去的岁月来看，Struts 1是所有MVC框架中不容辩驳的胜利者，不管是市场占有率，还是所拥有的开发人群，Struts 1都拥有其他MVC框架不可比拟的优势。Struts 1的成功得益于它丰富的文档、活跃的开发群体。当然，Struts 1是世界上第一个发布的MVC框架：Struts 1.0在2001年6月发布，这一点可能是使它得到如此广泛拥戴的主要原因。

为了使读者可以明白Struts 1的运行机制，下面将简要介绍Struts 1的基本框架。

Struts 1框架以ActionServlet作为核心控制器，整个应用由客户端请求驱动。当客户端向Web应用发送请求时，请求将被Struts 1的核心控制器ActionServlet拦截，ActionServlet根据请求决定是否需要调用业务逻辑控制器处理用户请求（实际上，业务逻辑控制器还是控制器，它只是负责调用模型来处理用户请求），当用户请求处理完成后，其处理结果通过JSP呈现给用户。

对于整个Struts 1框架而言，控制器就是它的核心，Struts 1的控制器由两个部分组成：核心控制器和业务逻辑控制器。其中核心控制器就是ActionServlet，由Struts 1框架提供；业务逻辑控制就是用户自定义的Action，由应用开发者提供。

对于大部分用户请求而言，都需要得到服务器的处理。当用户发送一个需要得到服务器处理的请求时，该请求被ActionServlet拦截到，ActionServlet将该请求转发给对应的业务逻辑控制器，业务逻辑控制器调用模型来处理用户请求；如果用户请求只是希望得到某个URL资源，则由ActionServlet将被请求的资源转发给用户。

Struts 1的程序运行流程如下图所示：  
 ![](https://www.isharkfly.com/images/transparent.png)

下面就Struts 1程序流程具体分析MVC中的三个角色。

（1）Model部分

Struts 1的Model部分主要由底层的业务逻辑组件充当，这些业务逻辑组件封装了底层数据库访问、业务逻辑方法实现。实际上，对于一个成熟的企业应用而言，Model部分也不是一个简单的JavaBean所能完成的，它可能是一个或多个EJB组件，可能是一个WebService服务。总之，Model部分封装了整个应用的所有业务逻辑，但整个部分并不是由Struts 1提供的，Struts 1也没有为实现Model组件提供任何支持。

（2）View部分

Struts 1的View部分采用JSP实现。Struts 1提供了丰富的标签库，通过这些标签库可以最大限度地减少脚本的使用。这些自定义的标签库可以输出控制器的处理结果。

虽然Struts 1提供了与Ties框架的整合，但Struts 1所支持的表现层技术非常单一：既不支持FreeMarker、Velocity等模板技术，也不支持JasperReports等报表技术。

（3）Controller部分

Struts 1的Controller由两个部分组成。

— 系统核心控制器：由Struts 1框架提供，就是系统中的ActionServlet。

— 业务逻辑控制器：由Struts 1框架提供，就是用户自己实现的Action实例。

Struts 1的核心控制器对应上图中的核心控制器（ActionServlet）。该控制器由Struts 1框架提供，继承HttpServlet类，因此可以配置成一个标准的Servlet，该控制器负责拦截所有HTTP请求，然后根据用户请求决定是否需要调用业务逻辑控制器，如果需要调用业务逻辑控制器，则将请求转发给Action处理，否则直接转向请求的JSP页面。

业务逻辑控制器负责处理用户请求，但业务逻辑控制器本身并不具有处理能力，而是调用Model来完成处理。

Struts 1提供了系统所需要的核心控制器，也为实现业务逻辑控制器提供了许多支持。因此，控制器部分就是Struts 1框架的核心。有时候，我们直接将MVC层称为控制器层。

提示 对于任何的MVC框架而言，其实只实现了C（控制器）部分，但它负责用控制器调用业务逻辑组件，并负责控制器与视图技术（JSP、FreeMarker和Velocity等）的整合。

（1）支持的表现层技术单一

Struts 1只支持JSP作为表现层技术，不提供与其他表现层技术，例如Velocity、FreeMarker等技术的整合。这一点严重制约了Struts 1框架的使用，对于目前的很多Java EE应用而言，并不一定使用JSP作为表现层技术。

虽然Struts 1处理完用户请求后，并没有直接转到特定的视图资源，而是返回一个ActionForward对象（可以理解ActionForward是一个逻辑视图名），在struts-config.xml文件中定义了逻辑视图名和视图资源之间的对应关系，当ActionServlet得到处理器返回的ActionForword对象后，可以根据逻辑视图名和视图资源之间的对应关系，将视图资源呈现给用户。

从上面的设计来看，不得不佩服Struts 1的设计者高度解耦的设计：控制器并没有直接执行转发请求，而仅仅返回一个逻辑视图名——实际的转发放在配置文件中进行管理。但因为Struts 1框架出现的年代太早了，那时候还没有FreeMarker、Velocity等技术，因而没有考虑与这些FreeMarker、Velocity等视图技术的整合。

提示 Struts 1已经通过配置文件管理逻辑视图名和实际视图之间的对应关系，只是没有做到让逻辑视图名可以支持更多的视图技术。

虽然Struts 1有非常优秀的设计，但由于历史原因，它没有提供与更多视图技术的整合，这严重限制了Struts 1的使用。

（2）与Servlet API严重耦合，难于测试

因为Struts 1框架是在Model 2的基础上发展起来的，因此它完全是基于Servlet API的，所以在Struts 1的业务逻辑控制器内，充满了大量的Servlet API。

看下面的Action代码片段：[code]//业务逻辑控制器必须继承Struts 1提供的Action类

public class LoginAction extends Action

{

```
//处理用户请求的execute方法

public ActionForward execute(ActionMapping mapping, ActionForm form, 

HttpServletRequest request, HttpServletResponse response)throws 

AuctionException

{

	//获取封装用户请求参数的ActionForm对象

	//将其强制类型转换为登录用的ActionForm

	LoginForm loginForm = (LoginForm)form;

	//当用户名为scott,密码为tiger时返回成功

	if ("scott".equals(loginForm.getUsername() 

				&& "tiger".equals(loginForm.getPassword())

				{

					//处理成功，返回一个ActionForward对象

					return mapping.findForward("success");

				}

				else

				{

					//处理失败，返回一个ActionForward对象

					return mapping.findForward("success");

				}

			}

		}[/code]对于Struts 1框架而言，因为它与JSP/Servlet耦合非常紧密，因而导致了许多不可避免的缺陷，随着Web应用的逐渐扩大，这些缺陷逐渐变成制约Struts 1发展的重要因素——这也是Struts 2出现的原因。下面具体分析Struts 1中存在的种种缺陷。

```

当我们需要测试上面Action类的execute方法时，该方法有4个参数：ActionMapping、ActionForm、HttpServletRequest和HttpServletResponse，初始化这4个参数比较困难，尤其是HttpServletRequest和HttpServletResponse两个参数，通常由Web容器负责实例化。

因为HttpServletRequest和HttpServletResponse两个参数是Servlet API，严重依赖于Web服务器。因此，一旦脱离了Web服务器，Action的测试非常困难。

（3）代码严重依赖于Struts 1 API，属于侵入式设计

正如从上面代码片段中所看到的，Struts 1的Action类必须继承Struts 1的Action基类，实现处理方法时，又包含了大量Struts 1 API：如ActionMapping、ActionForm和ActionForward类。这种侵入式设计的最大弱点在于，一旦系统需要重构时，这些Action类将完全没有利用价值，成为一堆废品。

可见，Struts 1的Action类这种侵入式设计导致了较低的代码复用。
