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 对象:
![](https://i-blog.csdnimg.cn/blog_migrate/cb9e22d6a2c7a5000b42323929e82a78.png)
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);
![](https://i-blog.csdnimg.cn/blog_migrate/c524169e0314f771791550348b7f7875.png)
//
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();
}
}
以上都是单步调试看到的,