Servlet API解耦的访问方式
为了避免与 Servlet API 耦合在一起, 方便 Action 做单元测试, Struts2 对 HttpServletRequest, HttpSession 和 ServletContext 进行了封装, 构造了 3 个 Map 对象来替代这 3 个对象, 在 Action 中可以直接使用 HttpServletRequest, HttpServletSession, ServletContext 对应的 Map 对象来保存和读取数据.
I:通过 ActionContext 访问 Web 资源
ActionContext 是 Action 执行的上下文对象, 在 ActionContext 中保存了 Action 执行所需要的所有对象, 包括 parameters, request, session, application 等.
获取 HttpSession 对应的 Map 对象:
public Map getSession()
获取 ServletContext 对应的 Map 对象:
public Map getApplication()
获取请求参数对应的 Map 对象:
public Map getParameters()
获取 HttpServletRequest 对应的 Map 对象:
public Object get(Object key): ActionContext 类中没有提供类似 getRequest() 这样的方法来获取 HttpServletRequest 对应的 Map 对象. 要得到 HttpServletRequest 对应的 Map 对象, 可以通过为 get() 方法传递 “request” 参数实现
获取 HttpSession 对应的 Map 对象:
public Map getSession()
获取 ServletContext 对应的 Map 对象:
public Map getApplication()
获取请求参数对应的 Map 对象:
public Map getParameters()
获取 HttpServletRequest 对应的 Map 对象:
public Object get(Object key): ActionContext 类中没有提供类似 getRequest() 这样的方法来获取 HttpServletRequest 对应的 Map 对象. 要得到 HttpServletRequest 对应的 Map 对象, 可以通过为 get() 方法传递 “request” 参数实现
II:通过实现 Aware 接口访问 Web 资源
ction 类通过可以实现某些特定的接口, 让 Struts2 框架在运行时向 Action 实例注入 parameters, request, session 和 application 对应的 Map 对象:

Servlet 耦合的访问方式 API
直接访问 Servlet API 将使 Action 与 Servlet 环境耦合在一起, 测试时需要有 Servlet 容器, 不便于对 Action 的单元测试.
直接获取 HttpServletRequest 对象:
ServletActionContext.getRequest()
直接获取 HttpSession 对象
ServletActionContext.getRequest().getSession()
直接获取 ServletContext 对象
ServletActionContext.getServletContext()
直接获取 HttpServletRequest 对象:
ServletActionContext.getRequest()
直接获取 HttpSession 对象
ServletActionContext.getRequest().getSession()
直接获取 ServletContext 对象
ServletActionContext.getServletContext()
通过实现 ServletRequestAware, ServletContextAware 等接口的方式
不推荐使用耦合的访问方式 特殊情况下需要使用Servlet API 的时候可以通过ServletActionContext.getXXX()的方式
Dispatcher管理调度 装配默认设置等等
public class Dispatcher {
//程序读取默认配置文件的顺序
private static final String DEFAULT_CONFIGURATION_PATHS = "struts-default.xml,struts-plugin.xml,struts.xml" ;
//读取设置配置参数
private void init_TraditionalXmlConfigurations() {
String configPaths = initParams.get("config" );
if (configPaths == null) {
configPaths = DEFAULT_CONFIGURATION_PATHS;
}
String[] files = configPaths.split("\\s*[,]\\s*" );
for (String file : files) {
if (file.endsWith(".xml" )) {
if ("xwork.xml" .equals(file)) {
configurationManager.addContainerProvider(createXmlConfigurationProvider(file, false));
} else { //在这里设置基本配置
configurationManager.addContainerProvider(createStrutsXmlConfigurationProvider(file, false, servletContext));
}
} else {
}
}
}
public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,
ActionMapping mapping, ServletContext context) {
//使用包装的模式把request对象包装成一个Map集合 可以去看RequestMap的实现源码
Map requestMap = new RequestMap(request);
Map params = new HashMap(request.getParameterMap());
Map session = new SessionMap(request);
Map application = new ApplicationMap(context);
//extraContext 把所有的Servlet的APi封装成一个Map中后,再放入到一个大的map中
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);

// String HTTP_REQUEST ="com.opensymphony.xwork2.dispatcher.HttpServletRequest"
在ognl的值栈中可以看到
//有xwork包装后的HttpServletRequest
extraContext.put(StrutsStatics. HTTP_REQUEST, request);
extraContext.put(StrutsStatics. HTTP_RESPONSE, response);
extraContext.put(StrutsStatics. SERVLET_CONTEXT, servletContext);
//这个Map的方式访问对象
extraContext.put( "request", requestMap);
extraContext.put( "session", sessionMap);
extraContext.put( "application", applicationMap);
extraContext.put( "parameters", parameterMap);
//把所有访问对象放入一个attr为key的map集合中去,(这也就是为什么我们可以用attr的方式访问域的对象值还有默认的搜索的顺序request,session,application,parameters)
AttributeMap attrMap = new AttributeMap(extraContext);
extraContext.put( "attr", attrMap);
return extraContext;
}
//包装request 成一个Map的结构,事实还是一个request对象进行操作
public class RequestMap extends AbstractMap implements Serializable {
private static final long serialVersionUID = -7675640869293787926L;
private Set<Object> entries;
private HttpServletRequest request ;
public RequestMap( final HttpServletRequest request) {
this.request = request;
}
public Object get(Object key) {
return request .getAttribute(key.toString());
}
public Object put(Object key, Object value) {
Object oldValue = get(key);
entries = null;
request.setAttribute(key.toString(), value);
return oldValue;
}
}
以上的执行都是在Struts 的StrutsPrepareAndExecuteFilter 过滤器中执行完成的还没有开始执行拦截器
当我们在一个action中实现了RequestAware的接口 在什么时候对我们的action实现注入Request的值呢?
这个注入在ServletConfigInterceptor拦截器中进行注入Request的 可以从源码中看到
public class ServletConfigInterceptor extends AbstractInterceptor implements StrutsStatics {
//这里就实现了所有你实现的 有关Servlet的API的接口的注入到你的action中的对象中
public String intercept(ActionInvocation invocation) throws Exception {
final Object action = invocation.getAction();
final ActionContext context = invocation.getInvocationContext();
//判断是否实现了 ServletRequestAware接口
if (action instanceof ServletRequestAware) {
HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST );
((ServletRequestAware) action).setServletRequest(request);
}
if (action instanceof ServletResponseAware) {
HttpServletResponse response = (HttpServletResponse) context.get(HTTP_RESPONSE );
((ServletResponseAware) action).setServletResponse(response);
}
if (action instanceof ParameterAware) {
((ParameterAware) action).setParameters((Map)context.getParameters());
}
if (action instanceof ApplicationAware) {
((ApplicationAware) action).setApplication(context.getApplication());
}
if (action instanceof SessionAware) {
((SessionAware) action).setSession(context.getSession());
}
if (action instanceof RequestAware) {
((RequestAware) action).setRequest((Map) context.get("request" ));
}
if (action instanceof PrincipalAware) {
HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST );
if(request != null) {
((PrincipalAware) action).setPrincipalProxy(new ServletPrincipalProxy(request));
}
}
if (action instanceof ServletContextAware) {
ServletContext servletContext = (ServletContext) context.get(SERVLET_CONTEXT );
((ServletContextAware) action).setServletContext(servletContext);
}
return invocation.invoke();
}
}
以上都是单步调试看到的,