在使用struts框架中,经常使用ServletActionContext.getRequest()获得request对象,现在就看看ServletActionContext.getRequest()源码:
/**
* Gets the HTTP servlet request object.
*
* @return the HTTP servlet request object.
*/
public static HttpServletRequest getRequest() {
return (HttpServletRequest) ActionContext.getContext().get(HTTP_REQUEST);
}
注释:这里很简单继续调用ActionContext中getContext()方法获取
ActionContext对象,在调用
ActionContext对象中get()获取request对象,下面详细看看:
public class ActionContext implements Serializable {
static ThreadLocal actionContext = new ThreadLocal();
Map<String, Object> context;
public ActionContext(Map<String, Object> context) {
this.context = context;
}
/**
* Returns the ActionContext specific to the current thread.
*
* @return the ActionContext for the current thread, is never <tt>null</tt>.
*/
public static ActionContext getContext() {
return (ActionContext) actionContext.get();
}
public Object get(String key) {
return context.get(key);
}
注释:(1)ActionContext类首先定义了一个类型ThreadLocal的actionContext对象,这样保证每个线程获得actionContext对象时安全。
(2)ActionContext类中getContext()方法,获取相应线程上ActionContext对象
(3)ActionContext类中定义了类型Map<String, Object>的context对象,context中保存了request,actionMapping等相应的信息
(4)ActionContext类中get()方法,在context获取key为HTTP_REQUEST = "com.opensymphony.xwork2.dispatcher.HttpServletRequest"对应的对象。
到这里分析完成获取request的整个过程,那是怎么添加进来的呢?
DefaultActionProxy中的execute()方法:
public String execute() throws Exception {
ActionContext nestedContext = ActionContext.getContext();
ActionContext.setContext(invocation.getInvocationContext()); 。。。 retCode = invocation.invoke()
这里设置ActionContext对象,然后执行action,看来很很合理啊!
public class DefaultActionInvocation implements ActionInvocation {
protected ActionContext invocationContext;
protected Map<String, Object> extraContext;
public DefaultActionInvocation(final Map<String, Object> extraContext, final boolean pushAction) {
DefaultActionInvocation.this.extraContext = extraContext;
DefaultActionInvocation.this.pushAction = pushAction;
}
public ActionContext getInvocationContext() {
return invocationContext;
}
public void init(ActionProxy proxy) {
this.proxy = proxy;
Map<String, Object> contextMap = createContextMap();
// Setting this so that other classes, like object factories, can use the ActionProxy and other
// contextual information to operate
ActionContext actionContext = ActionContext.getContext();
if (actionContext != null) {
actionContext.setActionInvocation(this);
}
createAction(contextMap);
if (pushAction) {
stack.push(action);
contextMap.put("action", action);
}
invocationContext = new ActionContext(contextMap);
invocationContext.setName(proxy.getActionName());
。。。。
}
protected Map<String, Object> createContextMap() {
Map<String, Object> contextMap;
if ((extraContext != null) && (extraContext.containsKey(ActionContext.VALUE_STACK))) {
// In case the ValueStack was passed in
stack = (ValueStack) extraContext.get(ActionContext.VALUE_STACK);
if (stack == null) {
throw new IllegalStateException("There was a null Stack set into the extra params.");
}
contextMap = stack.getContext();
} else {
// create the value stack
// this also adds the ValueStack to its context
stack = valueStackFactory.createValueStack();
// create the action context
contextMap = stack.getContext();
}
// put extraContext in
if (extraContext != null) {
contextMap.putAll(extraContext);
}
//put this DefaultActionInvocation into the context map
contextMap.put(ActionContext.ACTION_INVOCATION, this);
contextMap.put(ActionContext.CONTAINER, container);
return contextMap;
}
注释:(1)DefaultActionInvocation类变量extraContext类型为Map<String, Object>,保存整个actionContext相应的信息。
(2)DefaultActionInvocation类变量invocationContext,保存了ActionContext对象。
(3)DefaultActionInvocation的构造函数中,给变量extraContext赋值。
(4)DefaultActionInvocation的init()方法中创建ActionContext对象,并且赋值给变量invocationContext。
现在看看DefaultActionInvocation的创建的方法:请看《刨根问底-struts-serviceAction()创建并执行action》,现在我们就简单的看形参 Map<String, Object> extraContext开始创建的地方:
Dispatcher中serviceAction()方法:
Map<String, Object> extraContext = createContextMap(request, response, mapping, context);
public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,
ActionMapping mapping, ServletContext context) {
// request map wrapping the http request objects
Map requestMap = new RequestMap(request);
// parameters map wrapping the http parameters. ActionMapping parameters are now handled and applied separately
Map params = new HashMap(request.getParameterMap());
// session map wrapping the http session
Map session = new SessionMap(request);
// application map wrapping the ServletContext
Map application = new ApplicationMap(context);
Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context);
if (mapping != null) {
extraContext.put(ServletActionContext.ACTION_MAPPING, mapping);
}
return extraContext;
}
public HashMap<String,Object> createContextMap(Map requestMap,
Map parameterMap,
Map sessionMap,
Map applicationMap,
HttpServletRequest request,
HttpServletResponse response,
ServletContext servletContext) {
HashMap<String,Object> extraContext = new HashMap<String,Object>();
extraContext.put(ActionContext.PARAMETERS, new HashMap(parameterMap));
extraContext.put(ActionContext.SESSION, sessionMap);
extraContext.put(ActionContext.APPLICATION, applicationMap);
Locale locale;
if (defaultLocale != null) {
locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());
} else {
locale = request.getLocale();
}
extraContext.put(ActionContext.LOCALE, locale);
//extraContext.put(ActionContext.DEV_MODE, Boolean.valueOf(devMode));
extraContext.put(StrutsStatics.HTTP_REQUEST, request);
extraContext.put(StrutsStatics.HTTP_RESPONSE, response);
extraContext.put(StrutsStatics.SERVLET_CONTEXT, servletContext);
// helpers to get access to request/session/application scope
extraContext.put("request", requestMap);
extraContext.put("session", sessionMap);
extraContext.put("application", applicationMap);
extraContext.put("parameters", parameterMap);
AttributeMap attrMap = new AttributeMap(extraContext);
extraContext.put("attr", attrMap);
return extraContext;
}
上面的代码其实不难,就是各种map之间的关系,及其处理。请看:extraContext.put(StrutsStatics.HTTP_REQUEST, request);
这就是根源了。