刨根问底struts2

来源:互联网 发布:大学生找网络兼职 编辑:程序博客网 时间:2024/05/05 20:49

  MVC一探究竟之struts2

           最近一直在学习JAVAEE中的MVC框架的一些知识,笔者写这篇博客的目的是想系统的对struts2一些核心使用的东西做一个总结。

      在myeclipse中构建好struts2框架之后,web容器当中的配置文件web.xml会载入一段struts2的Filter过滤器配置:

     <filter>
  <filter-name>struts2</filter-name>
  <filter-class>
  org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
  </filter-class>
  </filter>
  <filter-mapping>
  <filter-name>struts2</filter-name>
  <url-pattern>/*</url-pattern>
<!--   这是个通用过滤的,没有先后次序问题,它的意思是凡是这个项目的这种类型的请求 /*(*代表所有的)就是说所有的这么项目的请求都会被捕捉,过滤 -->
  </filter-mapping>

  在服务器端会生成一个struts.xml文件,配置解释详见http://blog.csdn.net/zz_mm/article/details/5460397

另外在servletserver当中,我们需要编写Action.java和Baseaction.java类,我们会为每一个需要传递的参数建立get,set方法,以及在execute方法中执行你写的方法并返回 success视图。

我们都知道,在普通的java web当中,servlet与web容器JSP进行值间传递的都是用的http请求实现的,jsp页面中如表单提交利用Post方法提交,servlet在其方法中request.getParameter获取参数。但是在我们的struts2当中,并没有做相关的request请求去获取客户端的数据,那为什么JSP里的值能够传递到Action呢?(这里的Action类是你自己编写的servlet与下文介绍的Action不同)

           这里就牵涉到struts的一些原理性的东西:Struts2工作原理



ActionContextcleanup

        ActionContextcleanup能够延长action中属性的生命周期,包括自定义属性,以便在jsp页面中进行访问,让actionContextcleanup过滤器来清除属性,不让action自己清除。如果你要用SiteMesh或者其他过滤器,一般是放在FilterDispatcher或者是现在的StrutsPrepareAndExecuteFilter之前。在调用完所有过滤器的doFilter方法后,核心过滤器FilterDispatcher或者StrutsPrepareAndExecuteFilter会清空ActionContext,如果其他过滤器要一直使用value stack等struts的特性时,如果不用ActionContextCleanUp的话,便得不到想要的值。                   ActionContextCleanUp 的作用就是上面用粗体标注出来的那一句。它会在doFilter方法里设置一个计数器counter的初始值为1,有了这个值,后续的核心过滤器就不会清 空ActionContext,而是由之前的过滤器也就是ActionContextCleanUp来清空ActionContext。

ActionMapper 
        ActionMapper其实是HttpServletRequest和Action调用请求的一个映射,它屏蔽了Action对于Request等 java Servlet类的依赖。Struts2中它的默认实现类是DefaultActionMapper,ActionMapper很大的用处可以根据自己的需要来设计url格式,它自己也有Restful的实现,具体可以参考文档的docs\actionmapper.html。 
ActionProxy&ActionInvocation 
        Action的一个代理,由ActionProxyFactory创建,它本身不包括Action实例,默认实现DefaultActionProxy是由ActionInvocation持有Action实例。ActionProxy作用是如何取得Action,无论是本地还是远程。而 ActionInvocation的作用是如何执行Action,拦截器的功能就是在ActionInvocation中实现的。 
ConfigurationProvider&Configuration 
        ConfigurationProvider就是Struts2中配置文件的解析器,Struts2中的配置文件主要是尤其实现类 XmlConfigurationProvider及其子类StrutsXmlConfigurationProvider来解析。

1:客户端初始化一个指向Servlet容器(Tomcat)的请求。

2:容器(Container)通过web.xml映射请求。

3:请求先通过actionContextcleanup过滤器后在调用核心过滤器(FilterDispatcher核心控制器或StrutsPrepareAndExecuteFilter,Struts2.1以前调用FilterDispatcherStruts2.1以后调用StrutsPrepareAndExecuteFilter)。注:虽然查找很多资料一直无法确认jsp参数何时存储进interceptor stack,但我觉得因该就在这个过程里面。

4:StrutsPrepareAndExecuteFilter通过调用ActionMapper来确定调用哪个Action。

5:如果ActionMapper决定调用哪个Action,StrutsPrepareAndExecuteFilter会把请求交给ActionProxy。

6:ActionProxy通过ActionMapping(存储特定请求映射到特定Action的相关信息)和ConfigurationManager找到需要调用的Action类。这个过程相当于ActionProxy读取struts.xml文件获取action和interceptor stack的信息。

7:ActionProxy创建一个Actioninvaction实例。

8:Actioninvaction直接调用invoke方法进行循环执行interceptor(拦截器)。拦截器中的paramtersinterceptor拦截器会做这么一份工作: 

       如果package使用了ParameterIntercepter这个拦截器,OgnlValueStack会自动为Action中有set方法的属性 赋值(如果用了modeldriven,同样也会为实体中有set方法的属性赋值),赋值时,OGNL会将此时值栈中的action当做当前节点(默认情 况下在请求进入action之前,该action也会被放入值栈),然后访问它的成员属性的set方法,如果ognl的context中的参数在 action中找不到对应的set方法,就会抛出OgnlException这相当于interceptor stack信息通过set方法匹配到对应的Action参数,这就是为什么我们看不见客户端与服务器间的参数传递。

9:Actioninvaction调用真正的Action(即我们自己编写的servlet类)。Action执行完后,Actioninvaction通过同样的方式返回Action的结果回客户端。补充:在项目当中,自己编写的action类一般会继承Actionsupport类,Actionsupport实现了Action(并非自己创建)类的接口,在mvc框架开发当中,无论po持久层还是bo业务层,每一层都会有三个类的划分,即接口类,实现类,以及工厂类。原因都是为了降低耦合度,泛型定义接口类,实现类编译接口的方法,工厂类建立静态方法new对象,不过在spring框架中,工厂类被spring中替代(后面会讲到)。Action定义验证、保存恢复错误消息、获取本地文本、获取本地信息方法接口,Actionsupport负责实现,继承Actionsupport就能调用这些方法(一般为适应国际标准),另外,继承Actionsupport重写execute方法。在struts.xml中对应<action>标签中用method属性指定你自己的方法的话,默认就要找execute方法。

另外,众所周知,struts2,hibernate,spring都利用了反射机制,那struts2怎么实现反射的呢。Struts2再为每个Action链建立interceptor时,就利用的反射加载类创建对象。反射实现详见:https://www.zhihu.com/question/23305913/answer/77129820


以上见解,纯属个人见解,如有错误,还望提出你的意见。





      

1 0
原创粉丝点击