本篇将建立测试用例,在action中以打断点的形式查看ActionContext中的数据结构。
不管多线程的情况,就以当前线程来说
一、预先了解
在ActionConext中,每一个线程都有一些数据存放在其中,那么是怎么存放的呢?
在ActionContext类中有这么几行代码:
Map<String, Object> context; public Map<String, Object> getContextMap() { return context; }
现在先有这么一个概念,所有的的数据都存放在这个context中,至于为什么,后面再说。通过getContextMap可以拿到这个map对象。
二、搭建测试环境
1.使用struts2环境,这里直接靠myeclipse工具完成。
2.新建一个TestAction,作为测试的入口action,并且在里面放一个id属性,用来模拟action中的属性。
package com.aii.test.action; import java.util.Map; import com.opensymphony.xwork2.ActionContext; public class TestAction { private int id; public String execute() { System.out.println(id); Map map = ActionContext.getContext().getContextMap(); return null; } public void setId(int id) { this.id = id; } }
三、开始测试
1.在return null一行打上断点,debug
2.访问http://localhost:8080/OgnlAnalysis/TestAction.action?id=2
此时控制台打印2,说明接收到并且注入id=2。
3.观察debug界面
可看到内存里面有2个属性:
一个是当前对象this,这里就不说了。
另外一个是map,也就是Context.getContextMap得到的那个对象。下面主要说来说说这个对象。
四、分析OgnlContext
可以看到这个Map的真实类型是OgnlContext的,鼠标放在上面可以看到是全类名为ognl.OgnlContex,关于这个类,详细的可以看上一篇OgnlContext源码分析
源码比较简单,建议自己打开源代码看看。
dubug界面OgnlContext与OgnlContext源代码的属性还是一一对应的。至于这个属性名为什么比之前的多出一个下划线,可以可以认为是版本问题,也可以说是源代码问题,反正可以不管。打印一下map.getClass().getDeclaredFields()得到的属性名,可以看到是有下划线的,与debug界面上是一致的。
那么当前的action以及这个id存在map的哪个地方呢?
可以得出结论:action是存放在root上的。
五、OgnlContext中的values存的是什么?
上一篇里也说道,values是一个HashMap的结构,那么展开values,看到的就是这样的没错:
看过HashMap的肯定知道里面内容都存在table这个数组里面了,那么展开table:
这长的,果然是一张散列表,数据有点多,就挑几个眼熟的来看看:
先看角标1和2的:
1存放的key是一串字符串,大概的意思就是httpServletRequest,value是StrutsRequestWrapper这个类的源代码也非常简单,就是原先request的一个包装类。
2存放的还不止一个元素(有next),这里就看第一个,存放的是ApplicationMap,代表的是全局的一些数据属性。
基本上就是所有的原先servlet中能用到相关的对象都放到了value当中来了。
如果我访问的路径是http://localhost:8080/OgnlAnalysis/TestAction.action?id=2&name=jack
再看下table:
看来客户端传递过来的属性,不管在action中有无属性,在map中都有备份。
这个备份存在哪呢?
1.在ActionContext的map中
2.在这个map的key为_values的一个值中
3.这个值也是一个hashMap,在这个HashMap的key为parameter的值中
4.这个值还是一个hashMap,这个HashMap才是用来存放客户端传过来的各种参数的,通过key可以得到对应的值。
下一篇,再从Struts2的源代码以中看ActionContext的存储结构。