我们要从ActionContext开始说起,首先看StrutsPrepareAndExecuteFilter核心过滤器,也是整个程序的入口,doFilter()方法中的 ——->
prepare.createActionContext(request, response);
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
prepare.setEncodingAndLocale(request, response);
prepare.createActionContext(request, response);
prepare.assignDispatcherToThread();
if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
chain.doFilter(request, response);
} else {
request = prepare.wrapRequest(request);
ActionMapping mapping = prepare.findActionMapping(request, response, true);
if (mapping == null) {
boolean handled = execute.executeStaticResourceRequest(request, response);
if (!handled) {
chain.doFilter(request, response);
}
} else {
execute.executeAction(request, response, mapping);
}
}
} finally {
prepare.cleanupRequest(request);
}
}
进入PrepareOpreration类的createActionContext()方法。
public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
ActionContext ctx;
Integer counter = 1;
Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
if (oldCounter != null) {
counter = oldCounter + 1;
}
ActionContext oldContext = ActionContext.getContext();
//如果ActionContext 不为null的话,重新new一个,在这里我们也可看到,ActionContext的数据结构,HashMap,用于查询最快的集合类。这段代码的意义在于使每一次请求,每一个action,都有其对应的ActionContext
if (oldContext != null) {
// detected existing context, so we are probably in a forward
ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));
} else {
//如果为null通过IoC容器ContainerImpl中的getInstance()方法创建对应实例,值栈在这里创建完成
ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
//创建一个名字叫做extraContext的Map,里面存储了request,response,servletContext信息,并将其放入ActionContext
stack.getContext().putAll(dispatcher.createContextMap(request, response, null, servletContext));
ctx = new ActionContext(stack.getContext());
}
request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
ActionContext.setContext(ctx);
return ctx;
}
在上面的注释中,我们提到ActionContext的数据结构是HashMap,那么ValueStack的数据结构是怎样的?
进入createValueStack()方法,进入OgnlValueStackFactory类,这个类继承ValueStackFactory接口
public class OgnlValueStackFactory implements ValueStackFactory
进入ValueStackFactory 接口中发现,这个接口就是用来创建值栈的。
public interface ValueStackFactory {
ValueStack createValueStack();
ValueStack createValueStack(ValueStack stack);
}
回到OgnlValueStackFactory,找到createValueStack()方法.
public ValueStack createValueStack() {
ValueStack stack = new OgnlValueStack(xworkConverter, compoundRootAccessor, textProvider, allowStaticMethodAccess);
container.inject(stack);
stack.getContext().put(ActionContext.CONTAINER, container);
return stack;
}
进入OgnlValueStack的构造方法之中
protected OgnlValueStack(XWorkConverter xworkConverter, CompoundRootAccessor accessor, TextProvider prov, boolean allowStaticAccess) {
setRoot(xworkConverter, accessor, new CompoundRoot(), allowStaticAccess);
push(prov);
}
发现构造方法是protected 修饰符,我认为是确保了安全性,进入setRoot()方法。
protected void setRoot(XWorkConverter xworkConverter, CompoundRootAccessor accessor, CompoundRoot compoundRoot,
boolean allowStaticMethodAccess) {
//栈对象是一个CompountRoot类型的栈结构
this.root = compoundRoot;
//设定OGNL所需的MemeberAccess实现类
this.securityMemberAccess = new SecurityMemberAccess(allowStaticMethodAccess);
//创建OGNL的上下文
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);
}
这才是真正的OgnlValueStack的初始化过程,我们接下来进入CompoundRoot类
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);
}
}
发现这个类继承了ArrayList类,我们发现其实OgnlValueStack的底层实际上是通过链表实现的栈结构。
接下来,我们要往回走,回到OgnlValueStackFactory的createValueStack()方法
public ValueStack createValueStack() {
ValueStack stack = new OgnlValueStack(xworkConverter, compoundRootAccessor, textProvider, allowStaticMethodAccess);
//将返回的值栈对象注入容器
container.inject(stack);
//将容器存入上下文,也就是ActionContext
stack.getContext().put(ActionContext.CONTAINER, container);
return stack;
}
到这里ActionContext和值栈的初始化过程,以及他们之间的关系似乎已经弄清楚了,借用一张网上的图来说明他们之间的关系。
学习了值栈以后,引发了我的思考,xwork与ognl之间的信息是怎样交互的?他们之间的类型转换是怎样完成的?留待后续完成。