标点符(钱魏 Way)

MVC设计模式:Struts的Action思想

Struts实质就是MVC模式的体现;因为它强制把程序分成三层结构,大大提高了灵活性,使得程序更加利于开发、扩展和维护。

MVC包含三个基础部分:Model、View和Controller,这三个部分以最小的耦合协同工作,以增加程序的可扩展性和可维护性。各个部分的实现技术可以总结如下:

  1. Model: 封装了所有的商业逻辑以及规则。通常被JavaBean或EJB的EntityBean实现。
  2. View: 使用商业逻辑处理后的结果并构建呈现给客户端的响应。通常被JSP、Struts的TagLib实现。
  3. Controller:管理和控制所有用户和应用程序间的交互。通常被Struts的ActionServlet、Action实现。

通常是一个Servlet接收用户的请求并把所有的输入转交给实际工作的Model。最后调用JSP返回输出。概括起来MVC的优点主要有以下方面:

  1. 多个视图可以对应一个模型。按MVC设计模式,一个模型对应多个视图,可以减少代码的复制及代码的维护量,一旦模型发生改变,也易于维护。
  2. 模型返回的数据与显示逻辑分离。模型数据可以应用任何的显示技术,例如,使用JSP页面、Velocity模板或者直接产生Excel文档等。
  3. 应用被分隔为三层,降低了各层之间的耦合,提供了应用的可扩展性。
  4. 控制层的概念也很有效,由于它把不同的模型和不同的视图组合在一起,完成不同的请求。因此,控制层可以说是包含了用户请求权限的概念。
  5. MVC更符合软件工程化管理的精神。不同的层各司其职,每一层的组件具有相同的特征,有利于通过工程化和工具化产生管理程序代码。

Struts的基本执行流程

  1. 客户端发送请求;
  2. 请求先通过Filter Chain(ActionContextCleanUp–>FilterDispatcher);
  3. ActionContextCleanUp主要清理当前线程的ActionContext和Dispatcher;
  4. FilterDispatcher通过ActionMapper来决定这个Request需要调用哪个Action;
  5. 如果ActionMapper决定调用某个Action,FilterDispatcher把请求的处理交给ActionProxy,这儿已经转到它的Delegate–Dispatcher来执行;
  6. ActionProxy根据ActionMapping和ConfigurationManager找到需要调用的Action类;
  7. ActionProxy创建一个ActionInvocation的实例;
  8. ActionInvocation真正的Action,当然这涉及到相关拦截器的调用
  9. Action执行完毕,ActionInvocation创建Result并返回,当然,如果要在返回之前做些什么,可以实现PreResultListener。添加PreResultListener可以在Interceptor中实现。

  • 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来解析。
    Struts2(2.1.2)部分源码分析

从org.apache.struts2.dispatcher.FilterDispatcher开始

顺着流程我们看Disptcher的init方法。init方法里就是初始读取一些配置文件等,先看init_DefaultProperties,主要是读取properties配置文件。

打开DefaultPropertiesProvider

再来看init_TraditionalXmlConfigurations方法,这个是读取struts-default.xml和Struts.xml的方法。

对于其它配置文件只用StrutsXmlConfigurationProvider,此类继承XmlConfigurationProvider,而XmlConfigurationProvider又实现ConfigurationProvider接口。

  1. 类XmlConfigurationProvider负责配置文件的读取和解析;
  2. addAction()方法负责读取<action>标签,并将数据保存在ActionConfig中;
  3. addResultTypes()方法负责将<result-type>标签转化为ResultTypeConfig对象;
  4. loadInterceptors()方法负责将<interceptor>标签转化为InterceptorConfi对象;
  5. loadInterceptorStack()方法负责将<interceptor-ref>标签转化为InterceptorStackConfig对象;
  6. loadInterceptorStacks()方法负责将<interceptor-stack>标签转化成InterceptorStackConfig对象。

上面的方法最终会被addPackage()方法调用,将所读取到的数据汇集到PackageConfig对象中。来看下XmlConfigurationProvider的源代码。

init_CustomConfigurationProviders方式初始自定义的Provider,配置类全名和实现ConfigurationProvider接口,用逗号隔开即可。

现在再回到FilterDispatcher,每次发送一个Request,FilterDispatcher都会调用doFilter方法。

Dispatcher类的serviceAction方法:

第一句createContextMap()方法,该方法主要把Application、Session、Request的key value值拷贝到Map中,并放在HashMap中,可以参见createContextMap方法:

后面才是最主要的–ActionProxy,ActionInvocation。ActionProxy是Action的一个代理类,也就是说Action的调用是通过ActionProxy实现的,其实就是调用了ActionProxy.execute()方法,而该方法又调用了ActionInvocation.invoke()方法。归根到底,最后调用的是DefaultActionInvocation.invokeAction()方法。先看DefaultActionInvocation的init方法。

接下来看看DefaultActionInvocation 的invoke方法。

看程序中的if(interceptors.hasNext())语句,当然,interceptors里存储的是interceptorMapping列表(它包括一个Interceptor和一个name),所有的截拦器必须实现Interceptor的intercept方法,而该方法的参数恰恰又是ActionInvocation,在intercept方法中还是调用invocation.invoke(),从而实现了一个Interceptor链的调用。当所有的Interceptor执行完,最后调用invokeActionOnly方法来执行Action相应的方法。

action执行完了,还要根据ResultConfig返回到view,也就是在invoke方法中调用executeResult方法。

这样,一个Struts2的请求流程基本上就结束了。

参考链接:http://www.blogjava.net/myyate/articles/Struts2_source_java.html

码字很辛苦,转载请注明来自标点符《MVC设计模式:Struts的Action思想》

评论

  1. 冯正君 #1

    大神说的很好,看了受益匪浅。
    然后也许在写文章的时候会借用一二其中的理论总结,希望原作者批准。
    另外,之后要实现一个系统,也许之后会请教一二。 :idea:

    回复
    2016-05-6