續 init()
過濾器主要工作的方法doFilter():
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
try {
//獲得請求的url
String uri = RequestUtils.getUri(request);
//該請求被struts排除,將請求傳遞到過濾器鏈
if (this.excludedPatterns != null && this.prepare.isUrlExcluded(request, this.excludedPatterns)) {
LOG.trace("Request {} is excluded from handling by Struts, passing request to other filters", uri);
chain.doFilter(request, response);
} else {
//接受該請求,檢查是否是靜態資源
LOG.trace("Checking if {} is a static resource", uri);
boolean handled = this.execute.executeStaticResourceRequest(request, response);
if (!handled) {
//普通請求處理
LOG.trace("Assuming uri {} as a normal action", uri);
//準備工作
//設置編碼和地區信息
this.prepare.setEncodingAndLocale(request, response);
//設置上下文
this.prepare.createActionContext(request, response);
//保證線程安全的操作
this.prepare.assignDispatcherToThread();
//包裝請求
request = this.prepare.wrapRequest(request);
//獲得處理該請求的action
ActionMapping mapping = this.prepare.findActionMapping(request, response, true);
if (mapping == null) {
//無法處理,傳遞到下一個過濾器
LOG.trace("Cannot find mapping for {}, passing to other filters", uri);
chain.doFilter(request, response);
} else {
//處理請求
LOG.trace("Found mapping {} for {}", mapping, uri);
this.execute.executeAction(request, response, mapping);
}
}
}
} finally {
this.prepare.cleanupRequest(request);
}
}
目錄
找到處理請求的Action信息
ActionMapping mapping = this.prepare.findActionMapping(request, response, true);
package org.apache.struts2.dispatcher.PrepareOperation;
public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup) {
ActionMapping mapping = (ActionMapping)request.getAttribute("struts.actionMapping");
if (mapping == null || forceLookup) {
try {
//通過ActionMapper找到對應處理的Action信息
mapping = ((ActionMapper)this.dispatcher.getContainer().getInstance(ActionMapper.class)).getMapping(request, this.dispatcher.getConfigurationManager());
if (mapping != null) {
//將mapping放入request
request.setAttribute("struts.actionMapping", mapping);
}
} catch (Exception var6) {
if (this.dispatcher.isHandleException() || this.dispatcher.isDevMode()) {
//服務器內部錯誤,狀態碼500
this.dispatcher.sendError(request, response, 500, var6);
}
}
}
return mapping;
}
public class ActionMapping {
private String name;
private String namespace;
private String method;
private String extension;
private Map<String, Object> params;
private Result result;
...
}
通過dispatcher獲得container再獲得ActionMapper的操作在之前的文章中已經提及的很多了,這就是container的主要作用之一:獲取對象。 然後主要就是getMapper(request,this.dispatcher.getConfigurationManager()):
public class DefaultActionMapper implements ActionMapper {
public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) {
ActionMapping mapping = new ActionMapping();
String uri = RequestUtils.getUri(request);
//最大長度
int indexOfSemicolon = uri.indexOf(59);
uri = indexOfSemicolon > -1 ? uri.substring(0, indexOfSemicolon) : uri;
//對uri進行處理 如/index.jsp處理之後剩下null /Login處理剩下/Login 主要是去掉.action後綴
uri = this.dropExtension(uri, mapping);
if (uri == null) {
return null;
} else {
//分析獲得name和namespace屬性 /Login -> name = "Login" namespace = "/"
this.parseNameAndNamespace(uri, mapping, configManager);
//處理特殊參數
this.handleSpecialParameters(request, mapping);
//分析Action Name 主要是動態方法(屬性allowDynamicMethodCalls)如果不允許則不做任何操作
return this.parseActionName(mapping);
}
}
...
}
對於其中方法的具體實現,不再深入。
生成執行Action的代理
接下來爲:
doFilter():
this.execute.executeAction(request, response, mapping);
ExecuteOperation
public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
this.dispatcher.serviceAction(request, response, mapping);
}
Dispatcher
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
//獲得外部環境
Map<String, Object> extraContext = this.createContextMap(request, response, mapping);
//獲得值棧
ValueStack stack = (ValueStack)request.getAttribute("struts.valueStack");
boolean nullStack = stack == null;
if (nullStack) {
ActionContext ctx = ActionContext.getContext();
if (ctx != null) {
stack = ctx.getValueStack();
}
}
//將值棧放入上下文
if (stack != null) {
extraContext.put("com.opensymphony.xwork2.util.ValueStack.ValueStack", this.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();
//生成代理,關鍵步驟
ActionProxy proxy = ((ActionProxyFactory)this.getContainer().getInstance(ActionProxyFactory.class)).createActionProxy(namespace, name, method, extraContext, true, false);
request.setAttribute("struts.valueStack", proxy.getInvocation().getStack());
if (mapping.getResult() != null) {
Result result = mapping.getResult();
result.execute(proxy.getInvocation());
} else {
//處理請求
proxy.execute();
}
//
if (!nullStack) {
request.setAttribute("struts.valueStack", stack);
}
} catch (ConfigurationException var17) {
this.logConfigurationException(request, var17);
this.sendError(request, response, 404, var17);
} catch (Exception var18) {
var18.printStackTrace();
if (!this.handleException && !this.devMode) {
throw new ServletException(var18);
}
this.sendError(request, response, 500, var18);
} finally {
UtilTimerStack.pop(timerKey);
}
}
關鍵的一步就是生成代理對象proxy,在生成過程首先生成一個ActionInvocation對象,然後生成proxy,接着調用proxy.prepare()。
DefaultActionProxyFactory
public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) {
ActionInvocation inv = this.createActionInvocation(extraContext, true);
this.container.inject(inv);
return this.createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
}
protected ActionInvocation createActionInvocation(Map<String, Object> extraContext, boolean pushAction) {
return new DefaultActionInvocation(extraContext, pushAction);
}
public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {
DefaultActionProxy proxy = new DefaultActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
this.container.inject(proxy);
proxy.prepare();
return proxy;
}
關於ActionInvocation我們看看它擁有的一些字段信息:
public class DefaultActionInvocation implements ActionInvocation {
private static final Logger LOG = LogManager.getLogger(DefaultActionInvocation.class);
protected Object action;//action對象,處理請求
protected ActionProxy proxy;
protected List<PreResultListener> preResultListeners;
protected Map<String, Object> extraContext;
protected ActionContext invocationContext;
protected Iterator<InterceptorMapping> interceptors;//攔截器
protected ValueStack stack;//值棧
protected Result result;
protected Result explicitResult;
protected String resultCode;
protected boolean executed = false;
protected boolean pushAction = true;
protected ObjectFactory objectFactory;
protected ActionEventListener actionEventListener;
protected ValueStackFactory valueStackFactory;
protected Container container;
protected UnknownHandlerManager unknownHandlerManager;
protected OgnlUtil ognlUtil;
protected LazyParamInjector lazyParamInjector;
...
}
從Action、Interceptors可以看出,ActionInvocation對象描述了Action運行的整個過程。prepare()最主要的應該是獲取運行時的配置信息,也就是<pakage>中的<method><interceptor><result>等信息。
DefualtActionProxy
protected void prepare() {
String profileKey = "create DefaultActionProxy: ";
try {
UtilTimerStack.push(profileKey);
////這個主要從運行時的配置,也就是我們前面提到的DefaultConfiguration中的RuntimeConfiguration中獲得,ActionConfig中包含了interceptor、result、param等信息
//獲得該請求對應的運行時配置信息,其實也就是struts.xml配置的<action>信息
this.config = this.configuration.getRuntimeConfiguration().getActionConfig(this.namespace, this.actionName);
if (this.config == null && this.unknownHandlerManager.hasUnknownHandlers()) {
this.config = this.unknownHandlerManager.handleUnknownAction(this.namespace, this.actionName);
}
if (this.config == null) {
throw new ConfigurationException(this.getErrorMessage());
}
//如果method屬性爲空 則設置爲默認的"execute"
this.resolveMethod();
if (!this.config.isAllowedMethod(this.method)) {
throw new ConfigurationException(this.prepareNotAllowedErrorMessage());
}
//初始化invocation,包括interceptor的賦值
this.invocation.init(this);
} finally {
UtilTimerStack.pop(profileKey);
}
}
通過代理執行Action處理請求
最終調用了ActionInvocation的invoke()方法:
StrutsActionProxy
public String execute() throws Exception {
ActionContext previous = ActionContext.getContext();
ActionContext.setContext(this.invocation.getInvocationContext());
String var2;
try {
var2 = this.invocation.invoke();
} finally {
if (this.cleanupContext) {
ActionContext.setContext(previous);
}
}
return var2;
}
前面說了擁有一個Action實例和這個Action所依賴的攔截器實例。ActionInvocation會按照指定的順序去執行這些攔截器、Action以及相應的Result。
package com.opensymphony.xwork2.DefaultActionInvocation
public String invoke() throws Exception {
String profileKey = "invoke: ";
String var21;
try {
UtilTimerStack.push(profileKey);
if (this.executed) {
throw new IllegalStateException("Action has already executed");
}
//這裏是調用攔截器,注意interceptors是迭代器
if (this.interceptors.hasNext()) {
InterceptorMapping interceptorMapping = (InterceptorMapping)this.interceptors.next();
String interceptorMsg = "interceptorMapping: " + interceptorMapping.getName();
UtilTimerStack.push(interceptorMsg);
try {
Interceptor interceptor = interceptorMapping.getInterceptor();
if (interceptor instanceof WithLazyParams) {
interceptor = this.lazyParamInjector.injectParams(interceptor, interceptorMapping.getParams(), this.invocationContext);
}
//攔截器處理
this.resultCode = interceptor.intercept(this);
} finally {
UtilTimerStack.pop(interceptorMsg);
}
} else {
//!!!!
//執行action對應的方法並且返回狀態碼即對應<result>中SUCCESS等
this.resultCode = this.invokeActionOnly();
}
//獲得調用action之前的監聽器
if (!this.executed) {
if (this.preResultListeners != null) {
LOG.trace("Executing PreResultListeners for result [{}]", this.result);
Iterator i$ = this.preResultListeners.iterator();
while(i$.hasNext()) {
Object preResultListener = i$.next();
PreResultListener listener = (PreResultListener)preResultListener;
String _profileKey = "preResultListener: ";
try {
UtilTimerStack.push(_profileKey);
listener.beforeResult(this, this.resultCode);
} finally {
UtilTimerStack.pop(_profileKey);
}
}
}
//獲得結果
if (this.proxy.getExecuteResult()) {
this.executeResult();
}
this.executed = true;
}
var21 = this.resultCode;
} finally {
UtilTimerStack.pop(profileKey);
}
return var21;
}
會依次執行相關的interceptor,然後invokeActionOnly()方法執行了action的對應處理請求的方法,並且放回一個結果碼。
package com.opensymphony.xwork2.DefaultActionInvocation
public String invokeActionOnly() throws Exception {
return this.invokeAction(this.getAction(), this.proxy.getConfig());
}
protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
String methodName = this.proxy.getMethod();
LOG.debug("Executing action method = {}", methodName);
String timerKey = "invokeAction: " + this.proxy.getActionName();
try {
Throwable t;
try {
UtilTimerStack.push(timerKey);
Object methodResult;
try {
methodResult = this.ognlUtil.callMethod(methodName + "()", this.getStack().getContext(), action);
} catch (MethodFailedException var16) {
...
}
String var20 = this.saveResult(actionConfig, methodResult);
return var20;
} catch (NoSuchPropertyException var17) {
...
} catch (MethodFailedException var18) {
...
}
if (t instanceof Exception) {
throw (Exception)t;
} else {
throw var18;
}
} finally {
UtilTimerStack.pop(timerKey);
}
}
獲得Result
private void executeResult() throws Exception {
//包括location(資源地址)、編碼、端口等信息
this.result = this.createResult();
String timerKey = "executeResult: " + this.getResultCode();
try {
UtilTimerStack.push(timerKey);
if (this.result != null) {
//執行result
this.result.execute(this);
} else {
if (this.resultCode != null && !"none".equals(this.resultCode)) {
throw new ConfigurationException("No result defined for action " + this.getAction().getClass().getName() + " and result " + this.getResultCode(), this.proxy.getConfig());
}
if (LOG.isDebugEnabled()) {
LOG.debug("No result returned for action {} at {}", this.getAction().getClass().getName(), this.proxy.getConfig().getLocation());
}
}
} finally {
UtilTimerStack.pop(timerKey);
}
}
Result的實現類StrutsResultSupport、ServletDispatcherResult、ServletRedirectResult、ServletActionRedirectResult,看到這些名稱應該很熟悉,沒錯對應的應該是<result>中type屬性的值,也就是dispatcher、redirect、actionRedirect。在這裏我們的例子是登錄操作,最終調用的是ServletDispatcherResult.doExecute():
package org.apache.struts2.result;
public class ServletDispatcherResult extends StrutsResultSupport :
public void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
LOG.debug("Forwarding to location: {}", finalLocation);
PageContext pageContext = ServletActionContext.getPageContext();
if (pageContext != null) {
pageContext.include(finalLocation);
} else {
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
RequestDispatcher dispatcher = request.getRequestDispatcher(finalLocation);
if (StringUtils.isNotEmpty(finalLocation) && finalLocation.indexOf(63) > 0) {
String queryString = finalLocation.substring(finalLocation.indexOf(63) + 1);
HttpParameters parameters = this.getParameters(invocation);
Map<String, Object> queryParams = this.urlHelper.parseQueryString(queryString, true);
if (queryParams != null && !queryParams.isEmpty()) {
parameters = HttpParameters.create(queryParams).withParent(parameters).build();
invocation.getInvocationContext().setParameters(parameters);
invocation.getInvocationContext().getContextMap().put("parameters", parameters);
}
}
if (dispatcher == null) {
LOG.warn("Location {} not found!", finalLocation);
response.sendError(404, "result '" + finalLocation + "' not found");
return;
}
Boolean insideActionTag = (Boolean)ObjectUtils.defaultIfNull(request.getAttribute("struts.actiontag.invocation"), Boolean.FALSE);
if (!insideActionTag && !response.isCommitted() && request.getAttribute("javax.servlet.include.servlet_path") == null) {
request.setAttribute("struts.view_uri", finalLocation);
request.setAttribute("struts.request_uri", request.getRequestURI());
//請求派發
dispatcher.forward(request, response);
} else {
dispatcher.include(request, response);
}
}
}
可以看出主要的工作就是資源的定位和請求的派發。這就是整個請求處理過程的主要步驟和涉及到的代碼。具體框架對應的流程推薦參考這篇文章:https://blog.csdn.net/wjw0130/article/details/46371847