文章目录
  1. 请求-响应 实现模型
  2. XWork宏观视图
  3. 数据流体系
  4. 控制流体系
    1. 事件处理节点和事件驱动元素
    2. 核心事件处理节点和辅助事件驱动节点
  5. 数据流体系
    1. ActionContext
      1. 数据储存
      2. 数据共享空间
      3. 数据储存的内容
    2. ValueStack
      1. 基本概念
      2. 数据结构
      3. 计算功能
      4. ValueStack对OGNL计算规则的特点
      5. 栈顶元素和子栈
    3. 深入ValueStack实现
      1. CompoundRoot
      2. CompoundRootAccessor
  6. 控制流体系
    1. Action
    2. Interceptor
      1. 基本概念
      2. Interceptor的定义
    3. ActionInvocation
      1. ActionInvocation调度分析
    4. ActionProxy
      1. 定义

struts2系列——XWork

请求-响应 实现模型

  • 参数-返回值 模式

Public Return someMethod(Param param1, Param param2){}

  • Return:返回值:处理相应结果
  • someMethod:方法名:请求-响应处理载体
  • (Param param1, Param param2):方法参数:请求内容的映射

对象的方法称为请求-响应模式在Java世界中的一种直观抽象。这种直观并符合简单逻辑思维的抽象方法,应该说完全符合“简单是美”的最佳实践。

  • 参数-参数 模式

Servlet标准就是参数-参数模式,因此这种模式也被称为Servlet模式。doGet(HttpServletRequest,HttpServletResponse) : void

这种模式和参数-返回值模式不同之处在于,请求和响应都在参数中,而没有返回值。这种模式是最为基础的请求-响应的实现机制,也是底层规范不得不采用的实现机制,也是实现完整请求-响应机制的唯一请求。在大多数web开发框架中,已经不会看到Servlet模式,因为所有的框架都会基于这种模式为基础,将具体实现转换到其他的实现模式。

  • POJO 模式
1
2
3
4
5
6
7
8
9
10
11
12
13
Public class UserController{
Private String userName;
Private String password;
Public String Login(){
Return "success";
}
}

在POJO模式中请求参数和返回值以属性的方式展现,处理请求使用内部方法。这种模式和上面两种请求方法的最大不同在:进行请求响应的处理类自身是一个有状态的对象。

XWork宏观视图

a

数据流体系

数据流体系在上图中是横向的两个虚线框:ActionContext和ValueStack,他们之间是包含关系,ValueStack是ActionContext的一个组成部分。为何是包含关系?ActionContext提供了数据环境,他表现出来的空间概念,恰好称为数据载体进行储存的天然基石。ValueStack是一个具备表达式引擎计算能力的数据结构,表达式引擎是为了解决数据访问和数据传输之间的困境。那么一个提供数据环境,一个提供为静态环境添加动态计算功能,两者分别是数据和流,因此两者密不可分。

控制流体系

在上图中是实线的部分。在讨论控制流体系时,关注两个关系:事件处理节点和事件驱动元素之间的关系、核心事件处理节点和辅助事件处理节点。

事件处理节点和事件驱动元素

事件处理节点由Action/Interceptor/Result组成,事件处理驱动元素由ActionProxy和ActionInvocation组成。在XWork控制流中,事件处理驱动元素对事件处理节点元素形成调用关系。ActionInvocation是对事件处理节点的执行调度,XWork控制流体系的总调度。

核心事件处理节点和辅助事件驱动节点

核心事件处理节点和辅助事件处理节点就是Action和Interceptor。他们在上图中是包裹关系,一个Interceptor套着另一个Interceptor,一层接着一层,把Action包裹在最里面。这是一个“栈”结构。在这个栈结构,Action在最底层,Interceptor在外面。根据先进后出的特性,试图把Action对象拿出来时,必须把位于Action上所有Interceptor依次取出来执行。每个Interceptor除了需要完成自身逻辑以外,还需要指定下一步的执行对象。

ActionInvocation在对事件处理节点调度的时候,是将Action和Interceptor捆绑在一起调度的。

数据流体系

ActionContext

ActionContext作为数据环境,有两大职责:数据储存和数据共享

数据储存

ActionContext.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
public class ActionContext implements Serializable {
static ThreadLocal actionContext = new ThreadLocal();
public static final String ACTION_NAME = "com.opensymphony.xwork2.ActionContext.name";
public static final String VALUE_STACK = "com.opensymphony.xwork2.util.ValueStack.ValueStack";
public static final String SESSION = "com.opensymphony.xwork2.ActionContext.session";
public static final String APPLICATION = "com.opensymphony.xwork2.ActionContext.application";
public static final String PARAMETERS = "com.opensymphony.xwork2.ActionContext.parameters";
public static final String LOCALE = "com.opensymphony.xwork2.ActionContext.locale";
public static final String TYPE_CONVERTER = "com.opensymphony.xwork2.ActionContext.typeConverter";
public static final String ACTION_INVOCATION = "com.opensymphony.xwork2.ActionContext.actionInvocation";
public static final String CONVERSION_ERRORS = "com.opensymphony.xwork2.ActionContext.conversionErrors";
public static final String CONTAINER = "com.opensymphony.xwork2.ActionContext.container";
Map<String, Object> context;
public ActionContext(Map<String, Object> context) {
this.context = context;
}
public void setActionInvocation(ActionInvocation actionInvocation) {
this.put("com.opensymphony.xwork2.ActionContext.actionInvocation", actionInvocation);
}
public ActionInvocation getActionInvocation() {
return (ActionInvocation)this.get("com.opensymphony.xwork2.ActionContext.actionInvocation");
}
public void setApplication(Map<String, Object> application) {
this.put("com.opensymphony.xwork2.ActionContext.application", application);
}
public Map<String, Object> getApplication() {
return (Map)this.get("com.opensymphony.xwork2.ActionContext.application");
}
public static void setContext(ActionContext context) {
actionContext.set(context);
}
public static ActionContext getContext() {
return (ActionContext)actionContext.get();
}
public void setContextMap(Map<String, Object> contextMap) {
getContext().context = contextMap;
}
public Map<String, Object> getContextMap() {
return this.context;
}
public void setConversionErrors(Map<String, Object> conversionErrors) {
this.put("com.opensymphony.xwork2.ActionContext.conversionErrors", conversionErrors);
}
public Map<String, Object> getConversionErrors() {
Map<String, Object> errors = (Map)this.get("com.opensymphony.xwork2.ActionContext.conversionErrors");
if (errors == null) {
errors = new HashMap();
this.setConversionErrors((Map)errors);
}
return (Map)errors;
}
public void setLocale(Locale locale) {
this.put("com.opensymphony.xwork2.ActionContext.locale", locale);
}
public Locale getLocale() {
Locale locale = (Locale)this.get("com.opensymphony.xwork2.ActionContext.locale");
if (locale == null) {
locale = Locale.getDefault();
this.setLocale(locale);
}
return locale;
}
public void setName(String name) {
this.put("com.opensymphony.xwork2.ActionContext.name", name);
}
public String getName() {
return (String)this.get("com.opensymphony.xwork2.ActionContext.name");
}
public void setParameters(Map<String, Object> parameters) {
this.put("com.opensymphony.xwork2.ActionContext.parameters", parameters);
}
public Map<String, Object> getParameters() {
return (Map)this.get("com.opensymphony.xwork2.ActionContext.parameters");
}
public void setSession(Map<String, Object> session) {
this.put("com.opensymphony.xwork2.ActionContext.session", session);
}
public Map<String, Object> getSession() {
return (Map)this.get("com.opensymphony.xwork2.ActionContext.session");
}
public void setValueStack(ValueStack stack) {
this.put("com.opensymphony.xwork2.util.ValueStack.ValueStack", stack);
}
public ValueStack getValueStack() {
return (ValueStack)this.get("com.opensymphony.xwork2.util.ValueStack.ValueStack");
}
public void setContainer(Container cont) {
this.put("com.opensymphony.xwork2.ActionContext.container", cont);
}
public Container getContainer() {
return (Container)this.get("com.opensymphony.xwork2.ActionContext.container");
}
public <T> T getInstance(Class<T> type) {
Container cont = this.getContainer();
if (cont != null) {
return cont.getInstance(type);
} else {
throw new XWorkException("Cannot find an initialized container for this request.");
}
}
public Object get(String key) {
return this.context.get(key);
}
public void put(String key, Object value) {
this.context.put(key, value);
}
}

ActionContext真正用来储存的空间是一个Map类型的变量context,ActionContext将所有的对象用键值的方法储存在context中,另外还提供了存取这些对象的方式。

数据共享空间

数据共享就会导致外界获得了一个相同的储存空间的访问权,必然造成线程安全问题。

1
2
3
4
staticThreadLocal actionContext = new ThreadLocal();
public staticvoid setContext(ActionContext context) {
actionContext.set(context);
}

数据储存的内容

从ActionContext接口可以看出ActionContext究竟在初始化的时候放了什么样的对象进去。

对XWork框架对象的访问:getContainer/getValueStack/getActionInvocation

对数据对象的访问:getSession/getApplication/getParameters

ActionContext包含的访问接口是包罗万象的,针对这些数据对象的访问接口返回值均为map,意思是说存放于其中的数据与Web容器无关。看似不合理,却反映出ActionContext设计的严谨。ActionContext是XWork中定义的元素,而XWork是一个脱离web容器的框架,因此ActionContext若引入web对象,那就与XWork解耦的基本设计思想背道相驰。

XWork这个封装考虑了两个方面:

  • 封装后的数据保证了线程安全
  • 所有储存对象为Map,可以统一数据访问

ActionContext的数据要被外部访问,因此在设计上也考虑到了与web容器进行交互的可能。提供了一个与Web容器打交道的方案,XWork在ActionContext的基础上扩展了一个ServletActionContext子类,并在其中封装了与原生Web容器交互的接口。ServletActionContext.java

ValueStack

基本概念

是XWork对OGNL的扩展

数据结构

是一个栈结构,ValueStack.java中可以看出,ValueStack是一个基本的栈结构。具有下面两个特点

  • 可以存放多个对象
  • 先进后出

ValueStack的实现类在OgnlValueStack中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class OgnlValueStack implements Serializable, ValueStack, ClearableValueStack, MemberAccessValueStack {
private static final long serialVersionUID = 370737852934925530L;
private static Logger LOG = LoggerFactory.getLogger(OgnlValueStack.class);
private boolean devMode;
CompoundRoot root;
transient Map<String, Object> context;
Class defaultType;
Map<Object, Object> overrides;
transient OgnlUtil ognlUtil;
transient SecurityMemberAccess securityMemberAccess;
private static final String MAP_IDENTIFIER_KEY = "com.opensymphony.xwork2.util.OgnlValueStack.MAP_IDENTIFIER_KEY";
public static void link(Map<String, Object> context, Class clazz, String name) {
context.put("__link", new Object[]{clazz, name});
}
protected OgnlValueStack(XWorkConverter xworkConverter, CompoundRootAccessor accessor, TextProvider prov, boolean allowStaticAccess) {
this.setRoot(xworkConverter, accessor, new CompoundRoot(), allowStaticAccess);
this.push(prov);
}
protected OgnlValueStack(ValueStack vs, XWorkConverter xworkConverter, CompoundRootAccessor accessor, boolean allowStaticAccess) {
this.setRoot(xworkConverter, accessor, new CompoundRoot(vs.getRoot()), allowStaticAccess);
}
@Inject
public void setOgnlUtil(OgnlUtil ognlUtil) {
this.ognlUtil = ognlUtil;
}
protected void setRoot(XWorkConverter xworkConverter, CompoundRootAccessor accessor, CompoundRoot compoundRoot, boolean allowStaticMethodAccess) {
this.root = compoundRoot;
this.securityMemberAccess = new SecurityMemberAccess(allowStaticMethodAccess);
this.context = Ognl.createDefaultContext(this.root, accessor, new OgnlTypeConverterWrapper(xworkConverter), this.securityMemberAccess);
this.context.put("com.opensymphony.xwork2.util.ValueStack.ValueStack", this);
Ognl.setClassResolver(this.context, accessor);
((OgnlContext)this.context).setTraceEvaluations(false);
((OgnlContext)this.context).setKeepLastEvaluation(false);
}

在内部真正起作用的是CompoundRoot的数据结构,他继承了ArrayList。ArrayList是一个链表结构,只要通过对ArrayList中元素的相关操作,就可以实现“先进后出”的效果。

计算功能

上面是ValueStack作为Stack的数据结构,下面来看一看ValueStack的Value部分。

1
2
public Object findValue(String expr)
publicvoid setValue(String expr, Object value, boolean throwExceptionOnFailure)

可以看出ValueStack也可以计算表达式。因此ValueStack是一个栈的数据结构,同时他拥有表达式引擎计算能力。

因此ValueStack是:

  • XWork进行OGNL计算的场所
  • XWork进行数据访问的基础

ValueStack对OGNL计算规则的特点

OGNL在进行表达式计算时的基本逻辑是:从栈顶端开始对栈内每个元素进行表达式匹配运算,并返回第一个成功匹配的结果。因此ValueStack支持多个Root对象的OGNL操作的本质是栈内元素遍历。我们不关心ValueStack的元素顺序,因为OGNL表达式在ValueStack中能够返回多个值的可能性不大。

栈顶元素和子栈

我们知道ValueStack在内部维护的栈是一个ArrayList,因此可以通过数组下表访问到元素。

栈顶:数组下表为0的元素,也是最后一个被压入栈的元素,ValueStack为他定义了一个访问关键字:top

子栈:数组下表为1,2这样的元素。

ValueStack使用[1]~[n]表示所有子栈

子栈的特点:

  • 一个大小为N的ValueStack,除了自身外,有N-1个子栈
  • 每个子栈自身也是一个ValueStack,
  • 相当于递归数据结构

深入ValueStack实现

CompoundRoot

CompoundRoot是ValueStack核心数据结构。他是一个栈结构,本质上是一个ArrayList

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class CompoundRoot extends ArrayList {
public CompoundRoot() {
}
public CompoundRoot(List list) {
super(list);
}
public CompoundRoot cutStack(int index) {
return new CompoundRoot(this.subList(index, this.size()));
}
public Object peek() {
return this.get(0);
}
public Object pop() {
return this.remove(0);
}
public void push(Object o) {
this.add(0, o);
}
}

从源码角度看,CompoundRoot就是一个栈结构,有常规的peek(返回栈顶元素),入站出站规则。cutStack方法会返回一个新的CompundRoot,当需要对子栈进行访问时,会通过这个方法返回一个子栈的结构,再进行链式的递归调用。这一递归调用体现了ValueStack数据结构的精妙之处(递归数据结构)。

CompoundRootAccessor

OgnlValueStackFactory对ValueStack进行初始化,对OGNL的计算指定许多默认的实现方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
public class OgnlValueStackFactory implements ValueStackFactory {
private XWorkConverter xworkConverter;
private CompoundRootAccessor compoundRootAccessor;
private TextProvider textProvider;
private Container container;
private boolean allowStaticMethodAccess;
public OgnlValueStackFactory() {
}
@Inject
public void setXWorkConverter(XWorkConverter conv) {
this.xworkConverter = conv;
}
@Inject("system")
public void setTextProvider(TextProvider textProvider) {
this.textProvider = textProvider;
}
@Inject(
value = "allowStaticMethodAccess",
required = false
)
public void setAllowStaticMethodAccess(String allowStaticMethodAccess) {
this.allowStaticMethodAccess = "true".equalsIgnoreCase(allowStaticMethodAccess);
}
public ValueStack createValueStack() {
ValueStack stack = new OgnlValueStack(this.xworkConverter, this.compoundRootAccessor, this.textProvider, this.allowStaticMethodAccess);
this.container.inject(stack);
stack.getContext().put("com.opensymphony.xwork2.ActionContext.container", this.container);
return stack;
}
public ValueStack createValueStack(ValueStack stack) {
ValueStack result = new OgnlValueStack(stack, this.xworkConverter, this.compoundRootAccessor, this.allowStaticMethodAccess);
this.container.inject(result);
stack.getContext().put("com.opensymphony.xwork2.ActionContext.container", this.container);
return result;
}
@Inject
public void setContainer(Container container) throws ClassNotFoundException {
Set<String> names = container.getInstanceNames(PropertyAccessor.class);
Iterator i$;
String name;
Class cls;
if (names != null) {
i$ = names.iterator();
while(i$.hasNext()) {
name = (String)i$.next();
cls = Class.forName(name);
if (cls != null) {
if (Map.class.isAssignableFrom(cls)) {
PropertyAccessor var6 = (PropertyAccessor)container.getInstance(PropertyAccessor.class, name);
}
OgnlRuntime.setPropertyAccessor(cls, (PropertyAccessor)container.getInstance(PropertyAccessor.class, name));
if (this.compoundRootAccessor == null && CompoundRoot.class.isAssignableFrom(cls)) {
this.compoundRootAccessor = (CompoundRootAccessor)container.getInstance(PropertyAccessor.class, name);
}
}
}
}
names = container.getInstanceNames(MethodAccessor.class);
if (names != null) {
i$ = names.iterator();
while(i$.hasNext()) {
name = (String)i$.next();
cls = Class.forName(name);
if (cls != null) {
OgnlRuntime.setMethodAccessor(cls, (MethodAccessor)container.getInstance(MethodAccessor.class, name));
}
}
}
names = container.getInstanceNames(NullHandler.class);
if (names != null) {
i$ = names.iterator();
while(i$.hasNext()) {
name = (String)i$.next();
cls = Class.forName(name);
if (cls != null) {
OgnlRuntime.setNullHandler(cls, new OgnlNullHandlerWrapper((NullHandler)container.getInstance(NullHandler.class, name)));
}
}
}
if (this.compoundRootAccessor == null) {
throw new IllegalStateException("Couldn't find the compound root accessor");
} else {
this.container = container;
}
}
}

其中多次调用了compoundRootAccessor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
public class CompoundRootAccessor implements PropertyAccessor, MethodAccessor, ClassResolver {
private static final Logger LOG = LoggerFactory.getLogger(CompoundRootAccessor.class);
private static Map invalidMethods = new HashMap();
static boolean devMode = false;
public CompoundRootAccessor() {
}
@Inject("devMode")
public static void setDevMode(String mode) {
devMode = "true".equals(mode);
}
public void setProperty(Map context, Object target, Object name, Object value) throws OgnlException {
CompoundRoot root = (CompoundRoot)target;
OgnlContext ognlContext = (OgnlContext)context;
Iterator i$ = root.iterator();
while(i$.hasNext()) {
Object o = i$.next();
if (o != null) {
try {
if (OgnlRuntime.hasSetProperty(ognlContext, o, name)) {
OgnlRuntime.setProperty(ognlContext, o, name, value);
return;
}
if (o instanceof Map) {
Map<Object, Object> map = (Map)o;
map.put(name, value);
return;
}
} catch (IntrospectionException var10) {
;
}
}
}
Boolean reportError = (Boolean)context.get("com.opensymphony.xwork2.util.ValueStack.ReportErrorsOnNoProp");
String msg = "No object in the CompoundRoot has a publicly accessible property named '" + name + "' (no setter could be found).";
if (reportError != null && reportError) {
throw new XWorkException(msg);
} else {
if (devMode) {
LOG.warn(msg, new String[0]);
}
}
}
public Object getProperty(Map context, Object target, Object name) throws OgnlException {
CompoundRoot root = (CompoundRoot)target;
OgnlContext ognlContext = (OgnlContext)context;
if (name instanceof Integer) {
Integer index = (Integer)name;
return root.cutStack(index);
} else if (!(name instanceof String)) {
return null;
} else if ("top".equals(name)) {
return root.size() > 0 ? root.get(0) : null;
} else {
Iterator i$ = root.iterator();
while(true) {
Object o;
do {
if (!i$.hasNext()) {
return null;
}
o = i$.next();
} while(o == null);
try {
if (OgnlRuntime.hasGetProperty(ognlContext, o, name) || o instanceof Map && ((Map)o).containsKey(name)) {
return OgnlRuntime.getProperty(ognlContext, o, name);
}
} catch (OgnlException var10) {
if (var10.getReason() != null) {
String msg = "Caught an Ognl exception while getting property " + name;
throw new XWorkException(msg, var10);
}
} catch (IntrospectionException var11) {
;
}
}
}
}

CompoundRootAccessor对无论属性访问或者方法访问都做了重新定义。也就是说ValueStack进行Ognl计算时都会循环扫描CompoundRoot所有元素。

在对于ActionContext和ValueStack的关系上,他们是形影不离的。

ActionContext的创建,总是伴随着ValueStack的创建。

控制流体系

Action

方法主体:Action接口的具体实现类是Xwork进行核心业务逻辑处理的场所

运行参数:接口方法不包含参数,无论是请求参数还是响应返回数据都以Action中属性变量的形式出现。

返回值:返回值是一个字符串,表示一个业务逻辑是否成功的标志。

action的两个突破点:

  1. 突破了传统Servlet模式中响应对象对web容器的依赖
  2. 突破了传统Servlet模式中相依红对象无状态的限制

Action的两个特征:

  1. 属性特征:

Action主要表现了对象自身的状态,对象与其他对象之间的协作关系。

前者成为XWork进行数据访问的基础,后者成为对象之间协作关系的描述。

  1. 行为特征:

指对特定请求进行相应的过程。

Interceptor

基本概念

本质是一段代码可以通过定义一个组织点,来指定interceptor的代码逻辑在组织点元素的之前或者之后执行。

AOP相关概念:

切面:一个关注点的模块化,这个关注点的实现可能横切多个对象。模块化的过程由Interceptor来实现

连接点:程序执行过程中明确的点。

切入点:制定一个通知将被引发的一系列连接点集合。

通知:在特定的连接点,aop框架指定的动作。

从最上面的图,可以看出的Interceptor的特点:

  • 群居:同一时刻总有多个Interceptor对象同时存在并协作
  • 栈结构:Interceptor和Interceptor互相包裹形成栈结构,Action对象包裹在对底层,作为栈底。
  • 执行栈:Action Invocation所执行的调度逻辑,是针对整个栈结构。

Interceptor的定义

Interceptor源码是一个接口,有destory()、init()、intercept()方法,自己写一个简单的Interceptor源码,实现intercept,将Actioninvocation当做参数传入。原因是:

  • 便于Interceptor随时与控制流和数据流的其他元素沟通。因为SctionInvocation的操作接口中不仅仅包含控制员幻速Action和ActionProxy的访问接口,也包含了ActionContext和ValueStack的访问接口。
  • 便于ActionInvocation在Interceptor的内部进行执行调度。

方法内部只有一句invocation.invoke(); invoke是ActionInvocation的核心,意思是对Interceptor对象和Action对象共同构成的执行栈进行逻辑执行调度。

在Interceptor内部有两种不同的逻辑执行顺序:

  • 调用ActionInvocation的Invoke方法指定对执行栈进一步的调度执行。inteceptor在完成自身逻辑之后,有责任把执行的控制权交给执行栈的下一个元素继续执行,下一个元素不是action就是interceptor,形成了一个递归调用。invoke方法及时触发整个递归调用链的入口,调用的结果也是整个执行栈的执行结果。invoke方法的调用触发了执行栈中剩余interceptor对象和action对象的执行完成并返回结果。
  • 返回一个String类型的ResultCode来种终止执行栈的调用。

ActionInvocation

ActionInvocation在Xwork控制流中是核心调度器

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
publicinterface ActionInvocation extends Serializable {
Object getAction();//获取与当前绑定的action对象
boolean isExecuted();// 判断是否完成对Action和Result的调度执行
ActionContextgetInvocationContext();//获取当前半丁的actionContext
ActionProxy getProxy();//获取当前绑定的actionProxy对象
Result getResult() throwsException;//获取result对象
String getResultCode();//获取调度执行结果代码
void setResultCode(Stringvar1);// 设置调度执行的结果代码,往往用于重置Action对象
ValueStack getStack();//获取与当前绑定的ValueStack
void addPreResultListener(PreResultListener var1);//注册一个PreResultListener
String invoke() throwsException;//单单执行操作Action的接口
String invokeActionOnly() throws Exception;
void setActionEventListener(ActionEventListener var1);
void init(ActionProxy var1);
}

分类:

  • 对控制流 数据流元素的访问接口:getAction/getActionProxy/getStack
  • 对执行调度流程的扩展接口:addPreListener/setActionEventListener
  • 对执行栈进行调度的执行接口:invoke/invokeActionOnly

ActionInvocation调度分析

他的核心调度功能是通过invoke完成的。我们重新对invoke做一个解释

  • 如果执行栈中下一个元素是inteceptor对象,则执行该这个inteceptor
  • 如果执行栈中下一个元素是Action对象,那么执行该Action
  • 如果执行栈找不到下一个元素,那么执行终止,返回ResultCode
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public String invoke() throws Exception {
String profileKey = "invoke: ";
String var21;
try {
UtilTimerStack.push(profileKey);
if (this.executed) {
throw new IllegalStateException("Action has already executed");
}
if (this.interceptors.hasNext()) {
InterceptorMapping interceptor = (InterceptorMapping)this.interceptors.next();
String interceptorMsg = "interceptor: " + interceptor.getName();
UtilTimerStack.push(interceptorMsg);
try {
this.resultCode = interceptor.getInterceptor().intercept(this);
} finally {
UtilTimerStack.pop(interceptorMsg);
}
} else {
this.resultCode = this.invokeActionOnly();
}
if (!this.executed) {
if (this.preResultListeners != null) {
Iterator i$ = this.preResultListeners.iterator();
while(i$.hasNext()) {
Object preResultListener = (PreResultListener)i$.next();
PreResultListener listener = (PreResultListener)preResultListener;
String _profileKey = "preResultListener: ";
try {
UtilTimerStack.push(_profileKey);
listener.beforeResult(this, this.resultCode);
} finally {
UtilTimerStack.pop(_profileKey);
}
}
}
if (this.proxy.getExecuteResult()) {
this.executeResult();
}
this.executed = true;
}
var21 = this.resultCode;
} finally {
UtilTimerStack.pop(profileKey);
}
return var21;
}

intercept和invoke形成了一个递归调用。递归调用的嵌套执行使得递归调用逻辑为中心的代码段称为逻辑的分水岭。

ActionProxy

定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface ActionProxy {
Object getAction();
String getActionName();
ActionConfig getConfig();
void setExecuteResult(boolean var1);
boolean getExecuteResult();
ActionInvocation getInvocation();
String getNamespace();
String execute() throws Exception;
String getMethod();
}

ActionProxy和actioninvocation也是一个包罗万象的接口。

一方面ActionProxy对于调用者屏蔽了XWork的调用细节。

支持一下
扫一扫,支持forsigner