Struts Action实例化
1)Struts2的Action,配置在struts.xml文件中,web容器(这里我使用的是Tomcat)启动时,是不会初始化的,只有有web请求时,才会初始化相应的action,每一次请求都会有一个新的action被实例化,所以不用担心线程安全的问题。2)要使用Struts2必须要配置过滤器,过滤器在web.xml文件中配置。
1)Struts2的Action,配置在struts.xml文件中,web容器(这里我使用的是Tomcat)启动时,是不会初始化的,只有有web请求时,才会初始化相应的action,每一次请求都会有一个新的action被实例化,所以不用担心线程安全的问题。
2)要使用Struts2必须要配置过滤器,过滤器在web.xml文件中配置。
<!--
1、使用struts2必须有这个filter,而且必须拦截所有的web请求[/*],而且必须出现在所有的filter的最后一位
2、使用了struts2之后,就不需要自己设置请求编码了
3、现在用的StrutsPrepareAndExecuteFilter,是struts2.1以后的叫法
而在最开始,FilterDispatcher
-->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
配置<url-pattern>/*</url-pattern>是拦截所有的web请求。
最近要面试web开发的岗位,所以抽空看了一看Struts2.3.1.2的源码,顺便写了一个demo
其他知识点
1)在window下,可以在/bin/catalina.bate配置JVM参数,在linux下,可以在/bin/catalina.bsh配置JVM参数。
2)Tomcat启动的时候,会加载自身的web.xml和web应用的web.xml这两个配置文件的并集,包括里面配置的一些servlet。
3)在web应用程序中配置好StrutsPrepareAndExecuteFilter以及映射关系(拦截所有的web请求),自己实际debug调试源码,启动Tomcat,会执行StrutsPrepareAndExecuteFilter的init(FilterConfig filterConfig)方法(包括初始化disPatcher),Tomcat启动的过程中,会加载jsp文件,同时也会为每个jsp文件执行一次doFilter(ServletRequest req,ServletResponse res,FilterChain chain),包括上下文环境的准备,以及Action的映射关系(调用DefaultActionMapper中的getMapping方法获取ActionMapping)。Action的映射关系是读取Jsp页面配置的以.action结尾的action属性的配置。
4)此时Tomcat已经启动,View层,HTTP请求,触发一个action,就会执行一次doFilter方法,初始化上下文环境,以及寻找action对应的映射关系,最后再通过ObjectFactory的buildAction方法,实例化actionbean,最后压入到OGNL栈中,如果是同一个用户,点击同一个链接,会再一次的实例化一次actionbean,而不会用以前的那个,这样就不会担心线程的安全性。
5)Struts2 Action实例化的源码分析
1.StrutsPrepareAndExecuteFilter的doFilter方法
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
//上下文环境的准备
prepare.setEncodingAndLocale(request, response);
prepare.createActionContext(request, response);
prepare.assignDispatcherToThread();
if ( excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
chain.doFilter(request, response);
} else {
request = prepare.wrapRequest(request);
ActionMapping mapping = prepare.findActionMapping(request, response, true);
if (mapping == null) {
boolean handled = execute.executeStaticResourceRequest(request, response);
if (!handled) {
chain.doFilter(request, response);
}
} else {
//实例化action的入口
execute.executeAction(request, response, mapping);
}
}
} finally {
prepare.cleanupRequest(request);
}
}
2. ExecuteOperations的executeAction方法,直接调用Dispatcher的serviceAction方法,响应action服务。
/**
* Executes an action
* @throws ServletException
*/
public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
//实例化action的入口
dispatcher.serviceAction(request, response, servletContext, mapping);
}
3. Dispatcher中serviceAction
/**
* Load Action class for mapping and invoke the appropriate Action method, or go directly to the Result.
* <p/>
* This method first creates the action context from the given parameters,
* and then loads an <tt>ActionProxy</tt> from the given action name and namespace.
* After that, the Action method is executed and output channels through the response object.
* Actions not found are sent back to the user via the {@link Dispatcher#sendError} method,
* using the 404 return code.
* All other errors are reported by throwing a ServletException.
*
* @param request the HttpServletRequest object
* @param response the HttpServletResponse object
* @param mapping the action mapping object
* @throws ServletException when an unknown error occurs (not a 404, but typically something that
* would end up as a 5xx by the servlet container)
* @param context Our ServletContext object
*/
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,
ActionMapping mapping) throws ServletException {
Map<String, Object> extraContext = createContextMap(request, response, mapping, context);
// If there was a previous value stack, then create a new copy and pass it in to be used by the new Action
ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
boolean nullStack = stack == null;
if (nullStack) {
ActionContext ctx = ActionContext.getContext();
if (ctx != null) {
stack = ctx.getValueStack();
}
}
if (stack != null) {
extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));
}
String timerKey = "Handling request from Dispatcher";
try {
UtilTimerStack.push(timerKey);
String namespace = mapping.getNamespace();
String name = mapping.getName();
String method = mapping.getMethod();
Configuration config = configurationManager.getConfiguration();
ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
namespace, name, method, extraContext, true, false);
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
// if the ActionMapping says to go straight to a result, do it!
if (mapping.getResult() != null) {
Result result = mapping.getResult();
result.execute(proxy.getInvocation());
} else {
proxy.execute();
}
// If there was a previous value stack then set it back onto the request
if (!nullStack) {
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
}
} catch (ConfigurationException e) {
// WW-2874 Only log error if in devMode
if(devMode) {
String reqStr = request.getRequestURI();
if (request.getQueryString() != null) {
reqStr = reqStr + "?" + request.getQueryString();
}
LOG.error("Could not find action or result\n" + reqStr, e);
}
else {
if (LOG.isWarnEnabled()) {
LOG.warn("Could not find action or result", e);
}
}
sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);
} catch (Exception e) {
sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
} finally {
UtilTimerStack.pop(timerKey);
}
}
更多推荐
所有评论(0)