1、MVC只是概念, 我们用servlet也可以模拟MVC,但是如果有很多servlet的话,
存在的问题
- 在web.xml中的配置将会变得特别多的servlet配置,配置管理不方便
- 表单中的参数值,需要request.getParameter()一个一个的取,然后再new 对象传到Service层
- 将需要在页面上显示的参数存放到requset或session等, requset.setArrtibute()
- 页面跳转,request.getRequestDispatcher("/login_success.jsp").forward(request,response),如果不使用jsp, 使用模板,或json数据,数据流,如何方便切换
问题一:当浏览器发送一个Http请求,web容器是如何接收这个请求并指定相应的java类来执行业务逻辑并返回处理结果的?
这个问题,可以简称为URL Mapping问题,
地址映射
问题二:数据是如何从浏览器的表单传递到java对象,如何将一个字体符,转化为java对象结构,
页面数据转化为Java对象
问题三:web容器是一个多线程环境,针对每个Http请求,Web容器的线程池会分配一个特定的线程进行处理。如何保证在多线程下, 处理请示的Java类是线程安全的对象,如何保证数据的流转和访问都是线程安全的
问题四:View层的表现形式是多种多样的, 随着发展,MVC如何提供针对不同的视图,如:不使用jsp,使用模板,json等等
2、Struts2是一个运行于web容器的表示层框架,其核心作用是帮助我们处理Http请求
3、Struts2通过扩展实现Servlet标准来处理Http请求
4、Struts2在web.xml配置的filter,init方法只在项目启动的时候执行一次, struts2对其内置对象的创建和缓存,初始化struts2的容器。
doFilter方法处理Http请求,又分两个阶段:
a、http请求预处理:针对每个Http请求进行预处理,为真正的业务逻辑执行做数据环境和运行环境做准备。这个阶段的特点:依赖于Web容器,并时时刻刻与Web容器打交道作为主要的工作
b、XWork执行业务逻辑:在这个阶段,程序执行的控制权被移交给了XWork。Struts2在完成Http请求的预处理后,将Http请求中的数据封装成普通的Java对象,并由Xwork负责执行具体的业务逻辑。
5、程序代码的特点:不依赖于Web容器,完全由XWork框架驱动整个执行的过程。
可以看出Struts2的核心设计理念是在于解藕。
所谓解耦,实际上是尽可能地消除核心程序对外部运行环境的依赖,从而保证核心程序能够更加专注于应用程序的逻辑本身。在Struts2中, 我们所说的外部运行环境就是Web容器。
代码上解耦:struts2将第一阶段中的代码整合到struts2-core.jar,将第二阶段中的代码整合到xwork-core-2.2.1.jar
将逻辑分配到不同的执行阶段:struts2将处理数据的逻辑和处理业务的逻辑分配到2个同的执行阶段,使得我们对于代码逻辑的关注点更为清晰。
严格意义上的struts2,实际上由2个不同的框架所组成。一个是真正意义的struts2,另外一个是XWork。从职责上讲, XWork才真正实现MVC的框架,Struts2的工作是对Http请求进行一定处理后,委托XWork完成一步一步的逻辑处理。
将Web容器与MVC实现分离,是Struts2区别其他Web框架的最重要的特性。也是最值得口味的一个宏观设计思路。
6、请求响应有三种实现模式:三种模式都是基于Servlet(因为都要依赖于Serlet标准)
a、参数-返回值,如SpirngMVC:
public class UserAction {
public ModelAndView lgoin(String userName, String password){
//构建视图返回
ModelAndView modelAndView = new ModelAndView("inddex");
return modelAndView;
}
}
b、参数-参数模式,如:Servlet
参数列表:请求对象,响应对象
返回值:没有返回值
c、POJO模式,即Struts2的模式
将类的成员变量做为请求参数与返回值, 方法做为请求处理
7、请求响应模式的职责分离
a、数据流:请求内容,响应内容
b、控制流:请求处理方法,响应跳转处理
请求处理载体 —— 进行逻辑处理的场所
响应内容 —— 逻辑处理的结果数据
响应跳转处理 —— 逻辑处理完成后的程序流转方式
8、控制层的职责:
请求数据的接收
调用业务逻辑层处理
响应数据的收集
响应流程的控制
9、web页面参数传递,request中使用Map存放, 使用Map的缺点:
a、使用Map中的键值作为数据存取的依据,使得程序的可读性大降低
10、使用FormBean作为数据载体缺点
a、强制继承FormBean,强耦合struts1
b、如果表单中有复杂的数据,分别对应多个Java对象,使用struts1,将不同对象的属性,都归到一个FormBean下
11、POJO:Java简单对象, 即JavaBean,不继承其他的类
第7章 别具匠心 —— XWork设计原理
7.3 XWork概览
在了解了数据流和控制流的来龙去脉之后,我们再来看看XWork中实现这两大核心驱动力的编程元素以及它们之间的调用关系。相信有了之前所有的概念做铺垫,无论是XWork的宏观视图还是微观视图,读者理解起来应该可以驾轻就熟。
7.3.1 XWork的宏观视图
事实上,这张XWork的宏观示意图是整个XWork乃至整个Struts2的核心。此图内涵丰富,几乎涵盖了XWork的元素构成、XWork中元素的调用关系、XWork的执行层次以及XWork与外部调用接口之间的关系等所有XWork框架的核心内容。
大家对于这张示意图的第一印象一定是这张图中不同类型的框框(有虚线的,也有实线的)。而这些不同的框框所围起来的构成要素,实际上代表着XWork框架中三个不同的体系结构:
1. 核心分发器Dispatcher
核心分发器Dispatcher位于整个示意图的最外层的Web容器中,它本身不属于XWork框架的组成部分。我们在这里把它纳入到XWork宏观示意图中,并作为一个重要的组成体系的主要原因在于它在Struts2中有着非常重要的低位。被称之为核心分发器的Dispatcher运行于Web容器中,却成为了 XWork框架的调用者和驱动执行者。在图中,我们可以看到在核心分发器Dispatcher和下面的XWork元素之间有一条明显的虚线分割线作为它们之间的区分标志。
2. XWork的控制流体系
XWork的控制流体系是指XWork进行请求响应的一系列执行元素,这一系列执行元素包括: ActionProxy、ActionInvocation、Interceptor、Action和Result。这些元素位于图中的下半部分,并被一个实线框封装于内部,由ActionProxy驱动执行。它们之所以被称之为XWork的控制流体系,是因为这些元素是真正的请求响应的逻辑处理载体,控制着整个请求响应的执行过程。
3. XWork的数据流体系
XWork的数据流体系是只XWork在进行请求响应时所依赖的一个数据环境,而这个数据环境中包含了两大元素:ActionContext和ValueStack。 这两大元素在图中所在的位置也比较特殊,它们都被虚线框包含其中。ActionContext所在的虚线框同时囊括了XWork控制流体系中的所有元素;而ValueStack所在的虚线框则囊括了核心控制元素的Action。这表明XWork的数据流元素在不同的控制流执行元素之间形成了 有层次的共享,它虽然不直接参与控制流的执行体系,却是控制流执行过程中必不可少的核心依赖。
如果单单把重心放在XWork框架本身,我们可以发现XWork的体系结构正是按照控制流和数据流这两大核心驱动力进行划分的。结合核心分发器Dispatcher,我们可以归纳出这三大体系结构之间的层次关系:
- 调用关系
- 映衬关系
再来谈谈“映衬关系”。映衬关系则是一种非常微妙的关系。所谓“映衬”,实际上体现了一种“你中有我,我中有你”的水乳-交融的联系。XWork框架的控制流体系的执行基础是其数据流中的元素;而另外一个方面,失去了控制流的执行流程,数据流的所有元素也没有存在的意义了。
我们可以看到,“解耦合”这样一个开发中的最佳实践被XWork充分挖掘。XWork将数据流和控制流这两大驱动程序运行的基本力量进行物理隔离,将它们分派到不同的执行元素之上。但在运行期,两者又通过某种编程手段有机联系在了一起。这种看似很松,实际很紧的联系正是贯穿XWork框架总体设计的一个核心思想。
7.3.2 XWork的微观视图
7.3.2.1数据流元素
XWork的数据流体系,在图7-9中以虚线框的形式存在。我们可以在虚线框中看到构成数据流的两大元素:ActionContext和ValueStack:
1. ActionContext —— 数据环境
ActionContext是一个独立的数据结构,其主要作用是为XWork的执行提供数据环境。无论是请求的参数,还是处理的返回值,甚至一些原生的Web容器对象,都被封装于ActionContext的内部,成为了Struts2 / XWork执行时所依赖的数据基础。
2. ValueStack —— 数据访问环境
ValueStack本身是一个数据结构,其主要作用是用以对OGNL计算进行扩展。因而,位于ActionContext之中的ValueStack则赋予了ActionContext进行数据计算的功能,从而使得ValueStack自身成为了一个可以进行数据访问的环境。
在XWork对数据流的设计中,首要的考虑因素是功能性。根据之前我们对数据流的分析,构成数据流的元素,有两大基础的功能性要求: 数据存储和数据传输。如果我们仔细分析ActionContext和ValueStack这两大元素,我们会发现ActionContext刚好是一个数据存储的容器,而ValueStack则接过了数据传输的责任大旗。这两大元素的相互配合,很好地诠释了数据流的完整过程。
那么,XWork对于数据流的设计有什么独到之处呢?
downpour 写道
结论 XWork对于数据流设计的亮点,在于数据流元素被设计成独立的数据结构。
结合图7-6,我们可以看到数据流的主要构成:请求内容和响应内容。如果回顾一下传统的参数-返回值(Param-Return)模式和参数-参数(Param-Param)模式,我们会发现无论是请求内容还是响应内容,它们在表现形式上都作为方法(Method)的一个重要组成部分(要么作为方法的参数、要么就作为方法的返回值)。而 作为控制流主要载体的方法(Method)本身,对数据流元素形成了语法依赖。也就是说,在这种情况下,数据流和控制流之间是天然耦合的。因为作为控制流实现的主体方法,它与参数和返回值在语法层面被紧密联系在了一起。
而XWork采用了与控制流完全独立的对象实体来封装所有的数据流元素,并将控制流中的核心处理要素(Action)置于数据流之中,使两者形成水乳-交融的关系。这种设计的理念基于“解耦合”这样一个思想,使得原本无法分离的编程元素成为了形式上独立,运行上又紧密联系在一起的组件。这一点,正是XWork在数据流设计上的精华之处,也是读者需要细细品味的地方。
7.3.2.2控制流元素
XWork的控制流体系,在图7-9中以实线框的形式存在。我们在实线框中可以看到构成控制流的元素主要有五个:ActionProxy、ActionInvocation、Interceptor、Action和Result。
这五大元素从功能逻辑上进行划分,还可以分成两类:其中的Interceptor、Action和Result被用于定义事件处理的基本流程,我们称之为事件处理节点;ActionProxy和ActionInvocation在事件处理的过程中起到的作用主要是对事件处理节点进行调度执行,我们将其称之为事件处理驱动元素。
我们在7.2.3章节中曾经深入分析过控制流的内部实现细节,并归纳了控制流的四大职责。不过当时我们并没有点出其中蕴含的一个XWork设计中的潜台词:
downpour 写道
结论 结论:XWork认为,一个事件处理的流程是有规律并可以被继续细化的。
正是基于这样一个基本观点,XWork建立起了一套定义事件处理流程的方法,并将它们映射到具体的Java对象中去。
1. Action —— 核心处理类
Action是XWork所定义的一个核心的事件处理接口。这个接口定义仅仅定义了一个没有参数的响应方法,从而使得所有实现Action接口的事件处理类,都自然而然地工作在属性-行为模式之上。其中,响应方法的内部完成对核心业务的处理,而事件处理类的内部属性则成为了响应方法进行业务处理的数据来源和响应结果。
2. Interceptor —— 拦截器
Interceptor本身是AOP的概念,表示对程序的某个逻辑执行点进行拦截,从而能够在这个逻辑执行点之前、之后或者环绕着这个逻辑执行点进行逻辑扩展。在XWork中,Interceptor的拦截对象是核心处理类Action,从而在Action的周围定义了一个环绕的逻辑扩展层次,其主要作用就在于能够在核心处理类Action的执行之前、之后进行自定义的逻辑行为扩展。
Result —— 执行结果
Result是XWork定义用以对核心处理类Action执行完毕之后的响应处理动作。Result被定义为一个独立的逻辑执行层次,其主要作用是使核心处理类Action能够更加关注其核心业务流程的处理,而将程序的跳转控制逻辑交给Result来完成。
通过Action、Interceptor和Result这三大元素的相互配合,一个完整的事件处理流程就可以被定义为: 以Action为业务处理核心,Interceptor进行逻辑辅助,Result进行响应逻辑跳转的具有丰富的执行层次的事件处理体系。
如果回顾一下在7.2.3这一小节有关对控制流细节的描述,我们会发现三大元素的完整定义实际上完成了我们对事件处理流程进行规范化流程中的前两个步骤: 划分事件处理流程步骤和定义事件处理节点对象。而整个规范化流程中最为关键的步骤,也就是 组织事件处理节点对象的执行次序,XWork则通过另外两个辅助对象来完成:
1. ActionProxy —— 执行环境
ActionProxy是整个XWork框架的执行入口。ActionProxy的存在,相当于定义了一个事件处理流程的执行范围,规定在ActionProxy内部的一切都属于XWork框架的管辖范围,而在ActionProxy之外,则只能以调用者的身份,与整个XWork的事件执行体系进行通讯。因此,ActionProxy的主要作用就在于对外屏蔽整个控制流核心元素的执行过程,对内则为Action、Interceptor、Result等事件处理节点对象提供了一个无干扰的执行环境。
2. ActionInvocation —— 核心调度器
ActionInvocation是组织起Action、Interceptor、Result等事件处理节点对象执行次序的核心调度器。ActionInvocation被封装于ActionProxy的内部,成为了XWork内部真正事件处理流程的总司令,它的执行调度过程,实际上控制着整个XWork事件处理体系的执行命脉。
在XWork的微观构成中,我们可以发现XWork的设计理念始终是将逻辑职责分派到最合适的编程元素之上。或许在这里我们还无法具体体会出XWork对这些具体元素的划分依据,不过我们已经可以从这些元素的名称中看出它们在框架中所处的不同地位。在下一章中,我们将对这些元素进行详细解读。
【XWork控制流元素的一个形象比喻】
XWork控制流被划分为五大元素:Action、Interceptor、Result、ActionProxy、ActionInvocation。我们可以使用一个战斗序列,来对这五大元素之间的关系进行诠释。
每当一个战役打响的时候,总指挥部总是需要分派一个具体番号的部队(ActionProxy)来执行战斗。任何一支部队,都有主力军(Action)和策应部队(Interceptor)。主力军(Action)负责核心战斗,而策应部队(Interceptor)则负责对主力部队进行策应和援助。然而,所有的战斗指令都是由部队的指挥官(ActionInvocation)决定的。指挥官(ActionInvocation)是一个部队(ActionProxy)的核心,他将负责主力部队(Action)和策应部队(Interceptor)的调度。当一个战斗结束以后,指挥官(ActionInvocation)还要负责指挥部队下一步的动向(Result),是乘胜追击敌人,还是继续待命。