Struts2.3.14路由分析

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的编码方式和reponseLocale,具体内容不细分析

// prepare.createActionContext创建当前request线程的ActionContextThreadlocal修饰的线程隔离变量

//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,

//proxyprepare最后执行ActionInvocation.init

//proxyexecute最后执行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>}
}






你可能感兴趣的:(Struts2.3.14路由分析)