1. StrutsPrepareAndExecuteFilter DoFilter
//任何请求都会先执行Filter.doFilter方法
protected PrepareOperations prepare;
protected ExecuteOperations execute;
protected List<Pattern> excludedPatterns = null;
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 {
execute.executeAction(request, response, mapping);⑤
}
}
} finally {
prepare.cleanupRequest(request);
}
}
//① prepare.setEncodingAndLocale方法名可以看出,是设置request的编码方式和reponse的Locale,具体内容不细分析
//② prepare.createActionContext创建当前request线程的ActionContext,Threadlocal修饰的线程隔离变量
//③prepare.assignDispatcherToThread设置当前request线程的Dispather, Threadlocal维护的线程隔离变量
//④和⑤是分析request的uri,根据namespace和action,以及method,得到映射的jsp
2. PrepareOperations.findActionMapping
public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response) {
return findActionMapping(request, response, false);
}
public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup) {
ActionMapping mapping = (ActionMapping) request.getAttribute(STRUTS_ACTION_MAPPING_KEY);
if (mapping == null || forceLookup) {
try {
mapping = dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager());
if (mapping != null) {
request.setAttribute(STRUTS_ACTION_MAPPING_KEY, mapping);
}
} catch (Exception ex) {
dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
}
}
return mapping;
}
2.1 Dispatcher.getContainer方法
public Container getContainer() {
if (ContainerHolder.get() != null) {
return ContainerHolder.get();
}
ConfigurationManager mgr = getConfigurationManager();
if (mgr == null) {
throw new IllegalStateException("The configuration manager shouldn't be null");
} else {
Configuration config = mgr.getConfiguration();
if (config == null) {
throw new IllegalStateException("Unable to load configuration");
} else {
Container container = config.getContainer();
ContainerHolder.store(container);
return container;
}
}
}
public ConfigurationManager getConfigurationManager() {
return configurationManager;
}
2.1.1ConfigurationManager.getConfiguration
public synchronized Configuration getConfiguration() {
if (configuration == null) {
setConfiguration(createConfiguration(defaultFrameworkBeanName));
try {
configuration.reloadContainer(getContainerProviders());
} catch (ConfigurationException e) {
setConfiguration(null);
throw new ConfigurationException("Unable to load configuration.", e);
}
} else {
conditionalReload();
}
return configuration;
}
2.1.2 DefaultConfiguration.getContainer
public Container getContainer() {
return container;
}
public synchronized List<PackageProvider> reloadContainer(List<ContainerProvider> providers) throws ConfigurationException {
……
ContainerBuilder builder = new ContainerBuilder();
……
container = builder.create(false); //实际上是ContainerImpl
2.1.3 ContainerBuilder.Create
public Container create(boolean loadSingletons) {
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>ensureNotCreated();
created = true;
final ContainerImpl container = new ContainerImpl(
new HashMap<Key<?>, InternalFactory<?>>(factories));
if (loadSingletons) {
container.callInContext(new ContainerImpl.ContextualCallable<Void>() {
public Void call(InternalContext context) {
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span> for (InternalFactory<?> factory : singletonFactories) {
factory.create(context);
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span> }
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span> return null;
}
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>});
}
container.injectStatics(staticInjections);
return container;
}
2.2 ContainerImpl.getInstance(Class)
public <T> T getInstance( final Class<T> type ) {
return callInContext(new ContextualCallable<T>() {
public T call( InternalContext context ) {
return getInstance(type, context);
}
});
}
//这里从容器中拿到DefaultActionMapper的实例
2.3 DefaultActionMapper.getMapping
public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) {
ActionMapping mapping = new ActionMapping();
String uri = getUri(request);
int indexOfSemicolon = uri.indexOf(";");
uri = (indexOfSemicolon > -1) ? uri.substring(0, indexOfSemicolon) : uri;
uri = dropExtension(uri, mapping);
if (uri == null) {
return null;
}
parseNameAndNamespace(uri, mapping, configManager);
handleSpecialParameters(request, mapping);
return parseActionName(mapping);
}
//getUri取得当前访问路径URI
//dropExtension去掉URI后面的.action后缀
//parseNameAndNamespace获取NameSpace和Action Name
//parseActionName判断是否支持动态方法调用
3 ExecuteOperations.ExecuteAction
public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
dispatcher.serviceAction(request, response, servletContext, mapping);
}
3.1 Dispatcher.ServiceAction
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,
ActionMapping mapping) throws ServletException {
......
Configuration config = configurationManager.getConfiguration();
ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, method, extraContext, true, false);
......
if (mapping.getResult() != null) {
Result result = mapping.getResult();
result.execute(proxy.getInvocation());
} else {
proxy.execute();
}
......
//Container.getInstance(ActionProxyFactory)获取ActionProxyFactory类实例StrutsActionProxyFactory
//struts-default.xml中定义了
<bean type="com.opensymphony.xwork2.ActionProxyFactory" name="struts" class="org.apache.struts2.impl.StrutsActionProxyFactory"/>
3.1.1 StrutsActionProxyFactory.createActionProxy
调用父类DefaultActionProxyFactory.createActionProxy方法
public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) {
ActionInvocation inv = new DefaultActionInvocation(extraContext, true);
container.inject(inv);
return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
}
再调用自已重载的createActionProxy方法
public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {
StrutsActionProxy proxy = new StrutsActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
container.inject(proxy);
proxy.prepare();
return proxy;
}
//这里采用了动态代理,使用StrutsActionProxy代理了ActionInvocation,
//proxy的prepare最后执行ActionInvocation.init
//proxy的execute最后执行ActionInvocation.Invoke
3.1.2 StrutsActionProxy.prepare
protected void prepare() {
super.prepare();
}
调用父类DefaultActionProxy的prepare方法
protected void prepare() {
......
resolveMethod();//判断是否设置method 为默认值execute
invocation.init(this);
......
3.1.3 DefaultActionInvocation.init
public void init(ActionProxy proxy) {
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>......
createAction(contextMap);//根据Namespace, ActionName等参数得到Action实例
......
List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors());
interceptors = interceptorList.iterator();//得到interceptoerList
}
protected void createAction(Map<String, Object> contextMap) {
......
action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);
......
}
3.2 StrutsActionProxy.execute
public String execute() throws Exception {
......
return invocation.invoke();
}
3.2.1 DefaultActionInvocation.Invoke
public String invoke() throws Exception {
try {
......
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span> if (interceptors.hasNext()) {
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>final InterceptorMapping interceptor = interceptors.next();
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
} else {
resultCode = invokeActionOnly();
}
......
if (!executed) {
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>if (proxy.getExecuteResult()) {
executeResult();
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>}
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>executed = true
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>return resultCode;
......
}
//先执行Action的拦截器,当所有的拦截器执行完,再执行Action里面的method,最后执行result
public String invokeActionOnly() throws Exception {
return invokeAction(getAction(), proxy.getConfig());
}
protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>String methodName = proxy.getMethod();
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>Object methodResult = null;
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>Method method = null;
......
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>method = getAction().getClass().getMethod(methodName, EMPTY_CLASS_ARRAY);
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>if (!methodCalled) {
methodResult = method.invoke(action, EMPTY_OBJECT_ARRAY);//利用反射,执行action的methold
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>}
return saveResult(actionConfig, methodResult);
}
private void executeResult() throws Exception {
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>result = createResult();
......
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>result.execute(this);
......
}
public Result createResult() throws Exception {
if (explicitResult != null) {
Result ret = explicitResult;
explicitResult = null;
return ret;
}
ActionConfig config = proxy.getConfig();
Map<String, ResultConfig> results = config.getResults();//获取当前action的所有ResultConfig
......
ResultConfig resultConfig = null;
......
resultConfig = results.get(resultCode);//根据resultCode获取对应的resultConfig
//resultConfig = results.get("*");
if (resultConfig != null) {
return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());//根据resultConfig创建对应的Result
......
return null;
}
//最后执行对应的Result,struts默认的并且最常见的result就是ServletDispatcherResult
//struts-default.xml定义了
<result-types>
......
<result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>
......
3.3 ServletDispatcherResult.execute
调用父类StrutsResultSupport.execute
public void execute(ActionInvocation invocation) throws Exception {
lastFinalLocation = conditionalParse(location, invocation);
doExecute(lastFinalLocation, invocation);
}
调用自身的doExecute方法
public void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>......
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>PageContext pageContext = ServletActionContext.getPageContext();
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>if (pageContext != null) {
pageContext.include(finalLocation);
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>} else {
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
RequestDispatcher dispatcher = request.getRequestDispatcher(finalLocation);
......
if (!insideActionTag && !response.isCommitted() && (request.getAttribute("javax.servlet.include.servlet_path") == null)) {
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>request.setAttribute("struts.view_uri", finalLocation);
request.setAttribute("struts.request_uri", request.getRequestURI());
dispatcher.forward(request, response);//forward给对应的jsp
} else {
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>dispatcher.include(request, response);
}
<span style="color:#0800;"><span style="font-family:宋体;"> </span></span>}
}