struts2的出现必定有它的优势,而且他的市场现在已经远远的超过了struts1,那么在解释它的原理之前,我们首先来看一下struts2究竟有哪些优势呢?我们为什么要用struts2?
1、用struts2的目的~~
把请求和界面分开,struts框架具有组件的模块化,灵活性和重用性的优点,同时简化了基于MVC的web应用程序的开发。
2、那么struts2有哪些优点呢?
a.Struts框 架本身是使用Java Servlet和JavaServer Pages技术的一种Model-View-Controller(MVC)实现.通过使用Struts作为基础,开发者能够更专注于应用程序的商业逻辑。
b.提供了对MVC的一个清晰的实现,这一实现包含了很多参与对所以请求进行处理的关键组件,如:使用OGNL进行参数传递、拦截器 、全局结果与声明式异常 、taglib等等。
明确了这些优点,我们下面说说struts2的工作原理:
在struts2的应用中,从用户请求到服务器返回相应响应给用户端的过程中,包含了许多组件如:Controller、ActionProxy、ActionMapping、Configuration Manager、ActionInvocation、Inerceptor、Action、Result等。
(1) 客户端(Client)向Action发用一个请求(Request)
(2) Container(如Tomcat)通过web.xml映射请求,并获得控制器(Controller)的名字
(3) Container(如Tomcat)调用控制器(StrutsPrepareAndExecuteFilter或FilterDispatcher)。在Struts2.1以前调用FilterDispatcher,Struts2.1以后调用StrutsPrepareAndExecuteFilter,FilterDispatcher询问ActionMapper来决定这个请是否需要调用某个Action。
Struts 2框架由3个部分组成:核心控制器FilterDispatcher、业务控制器和用户实现的业务逻辑组件。在这3个部分里,Struts 2框架提供了核心控制器FilterDispatcher,而用户需要实现业务控制器和业务逻辑组件。 FilterDispatcher是控制器的核心,就是mvc中c控制层的核心。下面粗略的分析下我理解FilterDispatcher工作流程和原理:FilterDispatcher进行初始化并启用核心doFilter。该控制器作为一个Filter运行在Web应用中,它负责拦截所有的用户请求,当 用户请求到达时,该Filter会过滤用户请求。如果用户请求以action结尾,该请求将被转入Struts 2框架处理。
package com.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class Myfilter implements Filter { @Override public void destroy() { System.out.println("------Myfilter.destroy()----------"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("------Myfilter.doFilter()----------"); chain.doFilter(request, response); } @Override public void init(FilterConfig config) throws ServletException { config.getInitParameter("encoding"); System.out.println("------Myfilter.init()----------"); } }(4)(5)、如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy。
(6)、ActionProxy通过ConfigurationManager询问框架的配置文件,找到需要调用的Action类 ,这里,我们一般是从struts.xml配置中读取。
<action name="login" class="com.action.LoginAction"> <result name="success">/success.jsp</result> <result name="error" type="redirect">/error.jsp</result> <result name="checkError">/checkSession.jsp</result> <interceptor-ref name="defaultInterceptorStack"></interceptor-ref> </action>
(7) ActionProxy把request请求传递给ActionInvocation
(8) ActionInvocation依次调用action和interceptor
Interceptor的接口定义没有什么特别的地方,除了init和destory方法以外,intercept方法是实现整个拦截器机制的核心方法。而它所依赖的参数ActionInvocation则是我们之前章节中曾经提到过的著名的Action调度者。
我在这里需要指出的是一个很重要的方法invocation.invoke()。这是ActionInvocation中的方法,而ActionInvocation是Action调度者,所以这个方法具备以下2层含义(详细看DefaultActionInvocation源代码):
1. 如果拦截器堆栈中还有其他的Interceptor,那么invocation.invoke()将调用堆栈中下一个Interceptor的执行。
2. 如果拦截器堆栈中只有Action了,那么invocation.invoke()将调用Action执行。
3.
这是我的interceptor类:
/** * */ package com.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; /** * @author dandan * */ public class MyInterceptor implements Interceptor { /* (non-Javadoc) * @see com.opensymphony.xwork2.interceptor.Interceptor#destroy() */ @Override public void destroy() { System.out.println("-------destroy()--------"); } /* (non-Javadoc) * @see com.opensymphony.xwork2.interceptor.Interceptor#init() */ @Override public void init() { System.out.println("-------init()--------"); } /* (non-Javadoc) * @see com.opensymphony.xwork2.interceptor.Interceptor#intercept(com.opensymphony.xwork2.ActionInvocation) */ @Override public String intercept(ActionInvocation arg0) throws Exception { System.out.println("-------intercept()--------"); return null; } }这是我的配置文件:
<interceptors> <interceptor name="myInterceptor" class="MyInterceptor"></interceptor> <interceptor name="otherMyInterceptor" class="com.interceptor.OtherMyInterceptor"></interceptor> <interceptor-stack name="defaultInterceptorStack"> <!-- <interceptor-ref name="myInterceptor"></interceptor-ref> --> <interceptor-ref name="defaultStack"></interceptor-ref> </interceptor-stack> <interceptor-stack name="otherMyInterceptor"> <interceptor-ref name="otherInterceptor"></interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> </interceptor-stack> </interceptors> <default-interceptor-ref name="defaultInterceptorStack"></default-interceptor-ref>
(9) 根据action的配置信息,产生result
(10) Result信息返回给ActionInvocation
(11) 产生一个HttpServletResponse响应
(12) 产生的响应行为发送给客服端。
struts1与struts2对比
在Action实现类方面:
Struts1要求Action类继承一个抽象基类;Struts1的一个具体问题是使用抽象类编程 而不是接口。
Struts2 Action类可以实现一个Action接口,也可以实现其他接口,使可选和定制服务成为可能。Struts2 提供一个ActionSupport基类 去实现常用的接口。
线程模式方面:
Struts1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能做的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的;
Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。
Servlet依赖方面:
Struts1 Action依赖于Servlet API,因为Struts1 Action的execute方法中有HttpServletRequest和HttpServletResponse方法。
Struts2 Action 不再依赖于ServletAPI,从而允许Action脱离Web容器运行,从而降低了测试Action的难度。当然,如果Action 需要直接访问HttpServletRequest和HttpServletResponse参数,Struts2 Action仍然可以访问它们。但是,大部分时候,Action都无需直接访问 HttpServletRequest和HttpServletResponse,从而给开发者更多灵活的选择。
封装请求参数方面:
Struts1 使用ActionForm对象封装用户的请求参数,所有的ActionForm 必须继承一个基类:ActionForm。因此,开发者必须创建大量的ActionForm类封装用户请求参数。
Struts2 直接使用Action 属性来封装用户请求属性,避免了开发者需要大量开发ActionForm类的繁琐,Struts 2 提供了ModelDriven 模式,可以让开发者使用单独的Model 对象来封装用户请求参数,但该Model对象无须继承任何Struts2基类,是一个POJO,从而 降低了代码污染。
表达式语言方面:
Struts1 整合了JSTL,因此可以使用JSTL表达式语言。这种表达式语言有基本对象图遍 历,但在对集合和索引属性的支持上则功能不强
Struts2 可以是用JSTL,但它整合了一种更强大和灵活的表达式语言:OGNL(Object Graph Notation Language),因此,Struts2下的表达式语言功能更加强大。