ActionContext:
public class ActionContext implements Serializable {
static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>();//補充本質上就是一個ThreadLocal<T>將當前thread與entryT綁定
/**
* Constant for the name of the action being executed.
*/
public static final String ACTION_NAME = "com.opensymphony.xwork2.ActionContext.name";
/**
* Constant for the {@link com.opensymphony.xwork2.util.ValueStack OGNL value stack}.
*/
public static final String VALUE_STACK = ValueStack.VALUE_STACK;//其中
/**
* Constant for the action's session.
*/
public static final String SESSION = "com.opensymphony.xwork2.ActionContext.session";
/**
* Constant for the action's application context.
*/
public static final String APPLICATION = "com.opensymphony.xwork2.ActionContext.application";
/**
* Constant for the action's parameters.
*/
public static final String PARAMETERS = "com.opensymphony.xwork2.ActionContext.parameters";
/**
* Constant for the action's locale.
*/
public static final String LOCALE = "com.opensymphony.xwork2.ActionContext.locale";
/**
* Constant for the action's type converter.
*/
public static final String TYPE_CONVERTER = "com.opensymphony.xwork2.ActionContext.typeConverter";
/**
* Constant for the action's {@link com.opensymphony.xwork2.ActionInvocation invocation} context.
*/
public static final String ACTION_INVOCATION = "com.opensymphony.xwork2.ActionContext.actionInvocation";
/**
* Constant for the map of type conversion errors.
*/
public static final String CONVERSION_ERRORS = "com.opensymphony.xwork2.ActionContext.conversionErrors";
/**
* Constant for the container
*/
public static final String CONTAINER = "com.opensymphony.xwork2.ActionContext.container";
private Map<String, Object> context;//將不同的域統一管理
如何統一管理:
//以setSession為例
public void setSession(Map<String, Object> session) {
put(SESSION, session);
}
public void put(String key, Object value) {
context.put(key, value);
}
OgnlValueStack(valueStack)
public class OgnlValueStack implements Serializable, ValueStack, ClearableValueStack, MemberAccessValueStack {
public static final String THROW_EXCEPTION_ON_FAILURE = OgnlValueStack.class.getName() + ".throwExceptionOnFailure";
private static final long serialVersionUID = 370737852934925530L;
private static final String MAP_IDENTIFIER_KEY = "com.opensymphony.xwork2.util.OgnlValueStack.MAP_IDENTIFIER_KEY";
private static final Logger LOG = LoggerFactory.getLogger(OgnlValueStack.class);
CompoundRoot root;//
transient Map<String, Object> context;//context(即為ActionContext):
如何保證ActionContext線程安全:
public static ActionContext getContext() {
//獲取當前線程綁定的ActionContext對象
return actionContext.get();
}
簡述: Thread, ThreadLocal, ThreadLocalMap關系
//Thread下有個ThreadLocal.ThreadLocalMap threadlocals
//從上可看出ThreadLocal中有個靜態類ThreadLocalMap..
獲取value(ThreadLocal綁定的object:value)簡述:
1.ThreadLocal中通過t.threadlocals獲取tm
2.而ThreadLocalMap又通過ThreadLocal查詢value
誤區:ThreadLocalMap并非為簡單的Map
而是一個size+1的數組..
public class ThreadLocal<T> {
static class ThreadLocalMap {
/**
* The table, resized as necessary.
* table.length MUST always be a power of two.
*/
private Entry[] table;
private void set(ThreadLocal key, Object value) {
// We don't use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not.
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal k = e.get();
//如果已經存在就直接return
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
//不存在就new添加進數組或者
tab[i] = new Entry(key, value);
int sz = ++size;//后續步驟猜測:添加一個null進數組
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}