Struts2 之 对xwork的理解
对象的生命周期的管理是面向对象编程亘古不变的话题,从syntax的角度,面向对象的高级编程语言都是以“对象”为核心,而对象之间的继承关系、嵌套引用关系构成的对象树结构为我们进行对象级别的逻辑操作提供了足够的语法支持。而对象之间的这种复杂的关系也为对象生命周期的管理带了难题:
- 1.运行期,对象实例的创建和引用机制
- 2.对象及其关联对象之间的依赖处理机制。
为了解决这个难题,业界在程序逻辑中引进了一个额外的编程元素(Container),
(由一系列操作对象的接口构成其中至少包括获取对象实例和管理对象之间依赖关系的操作方法。)
首先让我们先看看Struts的这个Container的构造吧。
从框架的角度其实Struts2实际运行有2条主线和2个执行阶段。
Struts2的所有内容都无法逃脱这些概念存在。他们构成了Struts2的基本元素和运行机理。
第一条主线:Struts2的初始化:调用servlet之init方法执行。
该主线特点:
1.仅在web应用启动时执行一次
2.init方法执行失败将导致整个应用启动失败。这也是源于Filter这个servlet规范的基本运行特性。
Struts2这条初始化主线主要干的活:框架元素的初始化,包括框架内部许多内置对象的创建和缓存。
对框架的运行的必要条件进行控制(根据“开闭原则”框架的扩展开放保证了我们可以在应用层面对框架的运行参数以及执行模式进行定制,所以在这条主线中struts2也对这种定制化的正确性提供了运行时校验,如果失败,则web应用的启动也会失败。)
这条主线的顺利执行将会为之后的Http请求提供“舒适的”执行环境,注意这里的运行环境并不是Struts2的运行环境,这里的环境是建立在web Container之上,框架运行必须的内置对象的集合。本次初始化也是对这个建立在web container之上的Container的初始化。
初始化涉及class如下:
第二条主线:Struts2的http请求处理主线,包括对http请求的处理、对必要数据的处理和返回数据的处理全过程。
即:从满足StrutsPrepareAndExecuteFilter过滤url开始到dofilter方法执行。
本主线分两个执行阶段:
1.Http请求预处理 这也是程序的控制权真正在Strust2手上的时候。程序在这个阶段是依赖web Container的。
本阶段主要将分析http请求中以字符串形式的“弱类型”数据转换成以对象为载体的“强类型”数据,以及为运行环境做准备。
2.XWork终于粉墨登场啦 O(∩_∩)O~ XWork执行业务逻辑
这个阶段程序的控制权落入XWork之手。XWork依托于第一阶段封装的对象形式的数据,处理业务逻辑。
这个阶段程序完全跟web Container没啥关系了 这也是Struts2所说的之所以它不是不依赖于web Container的MVC框架的原因。
这也体现了Struts2的核心设计理念:消除了核心程序对于运行环境(Web Container)的依赖,也是Struts2解耦的过程。
1.代码角度的解耦:第一执行阶段的代码整合到struts2-core-2.3.16.1.jar第二执行阶段的代码整合到xwork-core-2.3.16.1.jar
2.逻辑角度的解耦:将处理数据的逻辑和处理业务的逻辑分成俩个不同的执行阶段处理。(但是现在红极一时的SpringMVC却又回归了 重新拥入了Web Container的大怀抱啦 (⊙o⊙)…)
第二阶段设计类如下:
了解了Struts2的大体流程,接下来我们再具体看一下XWork到底是怎么工作的。
首先,先让我们来看看XWork Container这个"大盒子"是怎么定义的吧
- public interface Container extends Serializable {
- /**
- * Default dependency name.
- */
- String DEFAULT_NAME = "default";
- /**
- * Injects dependencies into the fields and methods of an existing object.
- */
- void inject(Object o);
- /**
- * Creates and injects a new instance of type {@code implementation}.
- */
- <T> T inject(Class<T> implementation);
- /**
- * Gets an instance of the given dependency which was declared in
- * {@link com.opensymphony.xwork2.inject.ContainerBuilder}.
- */
- <T> T getInstance(Class<T> type, String name);
- /**
- * Convenience method. Equivalent to {@code getInstance(type,
- * DEFAULT_NAME)}.
- */
- <T> T getInstance(Class<T> type);
- /**
- * Gets a set of all registered names for the given type
- * @param type The instance type
- * @return A set of registered names or empty set if no instances are registered for that type
- */
- Set<String> getInstanceNames(Class<?> type);
- /**
- * Sets the scope strategy for the current thread.
- */
- void setScopeStrategy(Scope.Strategy scopeStrategy);
- /**
- * Removes the scope strategy for the current thread.
- */
- void removeScopeStrategy();
- }
- String DEFAULT_NAME = "default";//默认的对象获取标识
- void inject(Object o);//进行对象依赖注入的基本操作接口,作为参数的Object将被XWork Container进行处理,Object内部声明有@Inject的字段和方法,都将被注入受到“盒子”托管的对象,从而建立起依赖关系
- <T> T inject(Class<T> implementation);//创建一个类的实例并进行对象依赖注入
- <T> T getInstance(Class<T> type, String name);//根据type和name作为唯一标识获取声明在com.opensymphony.xwork2.inject.ContainerBuilder的对象实例
- <T> T getInstance(Class<T> type);//根据type和默认的DEFAULT_NAME 作为唯一标识获取“盒子”里的java类实例
- Set<String> getInstanceNames(Class<?> type);//通过type获取这个type对应“盒子”中注册过的name
- void setScopeStrategy(Scope.Strategy scopeStrategy);//设置当前线程的作用范围的策略
- void removeScopeStrategy();//删除当前线程的作用范围的策略
个人觉得这个Container于Spring中的BeanFactory有着异曲同工之妙。