在上一篇从struts2的action中看ActionContext的存储结构中已经看到ActionContext.getActionContext.getContextMap()得到的map的大体结构类型。
这篇将从源代码层面进行分析。
一、回顾
在上一篇中看到ActionContext中存放的是OgnlContext这个类,这个类的源代码,在OgnlContext源码分析中已经将的比较清楚了。那么值栈ValueStack到底是什么鬼。
二、ValueStack
我们就从ActionContext类中的getValueStack()方法入手:
public ValueStack getValueStack() { return (ValueStack) get(VALUE_STACK); } public Object get(String key) { return context.get(key); }看来要得到这个值栈,还是要从context这个所谓的map中去取。
这个context的实际类型是OgnlContext,还记得OgnlContext是由一系列保留的Object以及一个HashMap共同维护的:先找保留的key,找不到再去HashMap中去找。
这里的key为VALUE_STACK,是要从HashMap中取的(还记得这个HashMap的属性名为_values)
也就是说,ValueStack是藏在OgnlContext中_values属性的hashMap的key为VALUE_STACK对应的值中。
在action中打印一下ValueStack真实的类:
System.out.println(ActionContext.getContext().getValueStack().getClass()); //结果 //class com.opensymphony.xwork2.ognl.OgnlValueStack那么我们就打开OgnlValueStack来看里面的源代码。
三、OgnlValueStack
1.两个重要的属性
CompoundRoot root; transient Map<String, Object> context;
2.先来说说这个叫做root的属性:
CompoundRoot比较陌生,打开类看一下:
/* * Copyright 2002-2006,2009 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.opensymphony.xwork2.util; import java.util.ArrayList; import java.util.List; /** * A Stack that is implemented using a List. * * @author plightbo * @version $Revision: 894090 $ */ public class CompoundRoot extends ArrayList { public CompoundRoot() { } public CompoundRoot(List list) { super(list); } public CompoundRoot cutStack(int index) { return new CompoundRoot(subList(index, size())); } public Object peek() { return get(0); } public Object pop() { return remove(0); } public void push(Object o) { add(0, o); } }
3.再来看看这个context属性:
在OgnlValueStack的构造方法都调用的
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), securityMemberAccess); context.put(VALUE_STACK, this); Ognl.setClassResolver(context, accessor); ((OgnlContext) context).setTraceEvaluations(false); ((OgnlContext) context).setKeepLastEvaluation(false); }这里又多出一个Ognl工具类,先不用管具体的代码,只要知道Ognl.createDefaultContext他是产生了一个OgnlContext对象,然后返回。
应该还记得,OgnlContext这个类实现了Map接口,Map context=ognlContext是完全没问题。
到这里也要记住,root他放的是一个stack,context放的是一个OgnlContext
四、OgnlContext
再回来看下Ongl这个工具类是怎么初始化一个OgnlContext对象的。
public static Map createDefaultContext( Object root, ClassResolver classResolver, TypeConverter converter, MemberAccess memberAccess ) { return addDefaultContext( root, classResolver, converter, memberAccess, new OgnlContext() ); } public static Map addDefaultContext( Object root, ClassResolver classResolver, TypeConverter converter, MemberAccess memberAccess, Map context ) { OgnlContext result; if (!(context instanceof OgnlContext)) { result = new OgnlContext(); result.setValues(context); } else { result = (OgnlContext)context; } if (classResolver != null) { result.setClassResolver(classResolver); } if (converter != null) { result.setTypeConverter(converter); } if (memberAccess != null) { result.setMemberAccess(memberAccess); } result.setRoot(root); return result; }
参数太多不管,只要看到root传过来就行了。
然后在return之前调用了setRoot方法,什么意思呢?
在OgnlContext中的_root属性上放的是一个Stack,就是叫做CompoundRoot的那个东西。
五、总结
可以看到,OgnlContext、OgnlValueStack之间的互相引用有些复杂:
OgnlContext=保留字+HashMap
HashMap=key:value...+value_stack:ognlValueStack
保留字=其他保留字+CompoundRoot
OgnlValueStack=CompoundRoot+OgnlContext
上丑图: