Struts2工作机制源码分析

本文深入探讨了Struts2框架的整体工作流程,包括初始化配置、核心组件的作用及交互方式,以及一次HTTP请求的具体处理流程。特别关注了StrutsPrepareAndExecuteFilter、ActionContext和ActionInvocation等关键组件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Struts2整体工作流程

        先通过Struts2官网一张图整体把握其工作流程:


在Struts2较新版本中,核心控制器为StrutsPrepareAndExecuteFilter,而不再是FilterDispatcher,但Struts2的基本架构不变。

初始化

Struts2下的web.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" 
	xmlns="http://java.sun.com/xml/ns/j2ee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	<!-- Struts2核心控制器配置,一个Filter -->
	<filter>
		<filter-name>struts2</filter-name> 
		<!-- 注意在2.1.3以上版本需使用此class -->
		<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>

  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

Struts2核心配置文件struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
	<!-- 定义常量key-value,struts.properties文件中定义的属性会覆盖constant -->
	<constant name="struts.test" value="test1"/>
	
	<!-- package包含多个Action,一个Action对应一个类的某个方法
		 package的名字必须是唯一的,package可以扩展
         name:package名称
         extends:继承的父package的配置
         abstract:设置package的属性为抽象的,抽象的package不能定义action,值true:false
         namespace:package命名空间,例如/test映射的url地址为http://localhost:8080/struts2/test/XX.action
     -->
	<package name="org_test_action" namespace="/test" extends="struts-default">
		<!-- 定义拦截器、拦截器栈 -->
		<interceptors>
			<interceptor name="logInterceptor" class="org.test.action.LogInterceptor"/>
			<interceptor name="timeInterceptor" class="org.test.action.TimeInterceptor" />
			<interceptor-stack name="interStack">
				<interceptor-ref name="logInterceptor" />
				<interceptor-ref name="timeInterceptor"/>
			</interceptor-stack>
		</interceptors> 
		
		<!-- 定义org_test_action package下的默认拦截器,当action没有定义拦截器的时候会用到 -->
		<default-interceptor-ref name="timeInterceptor"/>
		
		<!-- 定义全局的exception映射 -->
		<global-exception-mappings>
			<exception-mapping result="error" exception="java.lang.Exception"></exception-mapping>
		</global-exception-mappings>
		
		<!-- 一个Action对应一个类的某个方法 -->
		<action name="testaction" class="org.test.action.TestAction" method="execute">
			<!-- testaction的异常映射,范围包括RuntimeException及其子类 -->
			<exception-mapping result="error" exception="java.lang.RuntimeException"></exception-mapping>
			<!-- 拦截器有重叠的情况下则合并 -->
			<interceptor-ref name="defaultStack"/>
			<interceptor-ref name="interStack"/>
			<result name="success">/WEB-INF/page/test.jsp</result>
			<result name="error">/WEB-INF/page/error.jsp</result>
			<!-- 设置TestAction的url属性 -->
			<param name="url">http://www.sina.com</param>
		</action>
	</package>
</struts>
初始化调用栈


时序图

         初始化整体流程:


         init_PreloadConfiguration详细过程:


相关源码

/** StrutsPrepareAndExecuteFilter.java */
public void init(FilterConfig filterConfig) throws ServletException {
	InitOperations init = new InitOperations();
	Dispatcher dispatcher = null;
	try {
		FilterHostConfig config = new FilterHostConfig(filterConfig);
		init.initLogging(config);
		// 初始化核心工作,解析相关配置文件,创建Container等
		dispatcher = init.initDispatcher(config);
		init.initStaticContentLoader(config, dispatcher);

		prepare = new PrepareOperations(dispatcher);
		execute = new ExecuteOperations(dispatcher);
		this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);

		postInit(dispatcher, filterConfig);
	} finally {
		if (dispatcher != null) {
			// 清空ContainerHolder中缓存的Container
			dispatcher.cleanUpAfterInit();
		}
		// ActionContext.setContext(null);
		init.cleanup();
	}
}

/** InitOperations.java */
private Dispatcher createDispatcher( HostConfig filterConfig ) {
	// 获取web.xml中<filter>配置中的<init-param>键值对
	Map<String, String> params = new HashMap<String, String>();
	for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) {
		String name = (String) e.next();
		String value = filterConfig.getInitParameter(name);
		params.put(name, value);
	}
	// new Dispatcher
	return new Dispatcher(filterConfig.getServletContext(), params);
}

/** Dispatcher.java */
protected ConfigurationManager createConfigurationManager(String name) {
	return new ConfigurationManager(name);
}

// configurationManager添加FileManagerProvider、FileManagerFactoryProvider
private void init_FileManager() throws ClassNotFoundException {
	// configurationManager添加FileManagerProvider
	if (initParams.containsKey(StrutsConstants.STRUTS_FILE_MANAGER)) {
		final String fileManagerClassName = initParams.get(StrutsConstants.STRUTS_FILE_MANAGER);
		final Class<FileManager> fileManagerClass = (Class<FileManager>) Class.forName(fileManagerClassName);
		if (LOG.isInfoEnabled()) {
			LOG.info("Custom FileManager specified: #0", fileManagerClassName);
		}
		configurationManager.addContainerProvider(new FileManagerProvider(fileManagerClass, fileManagerClass.getSimpleName()));
	} else {
		// add any other Struts 2 provided implementations of FileManager
		configurationManager.addContainerProvider(new FileManagerProvider(JBossFileManager.class, "jboss"));
	}
	// configurationManager添加FileManagerFactoryProvider
	if (initParams.containsKey(StrutsConstants.STRUTS_FILE_MANAGER_FACTORY)) {
		final String fileManagerFactoryClassName = initParams.get(StrutsConstants.STRUTS_FILE_MANAGER_FACTORY);
		final Class<FileManagerFactory> fileManagerFactoryClass = (Class<FileManagerFactory>) Class.forName(fileManagerFactoryClassName);
		if (LOG.isInfoEnabled()) {
			LOG.info("Custom FileManagerFactory specified: #0", fileManagerFactoryClassName);
		}
		configurationManager.addContainerProvider(new FileManagerFactoryProvider(fileManagerFactoryClass));
	}
}

// configurationManager添加DefaultPropertiesProvider,用于加载org/apache/struts2/default.properties
private void init_DefaultProperties() {
	configurationManager.addContainerProvider(new DefaultPropertiesProvider());
}

// configurationManager添加XmlConfigurationProvider,用于加载struts-default.xml,struts-plugin.xml,struts.xml
private void init_TraditionalXmlConfigurations() {
	String configPaths = initParams.get("config");
	if (configPaths == null) {
		//configPaths = "struts-default.xml,struts-plugin.xml,struts.xml"
		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 {
			throw new IllegalArgumentException("Invalid configuration file name");
		}
	}
}

protected XmlConfigurationProvider createStrutsXmlConfigurationProvider(String filename, boolean errorIfMissing, ServletContext ctx) {
	return new StrutsXmlConfigurationProvider(filename, errorIfMissing, ctx);
}

//configurationManager添加PropertiesConfigurationProvider,用于加载struts.properties
private void init_LegacyStrutsProperties() {
	configurationManager.addContainerProvider(new PropertiesConfigurationProvider());
}

// 初始化<filter>配置中的<init-param> configProviders配置,添加到configurationManager,用于加载用户自定义的ConfigurationProvider
private void init_CustomConfigurationProviders() {
	String configProvs = initParams.get("configProviders");
	if (configProvs != null) {
		String[] classes = configProvs.split("\\s*[,]\\s*");
		for (String cname : classes) {
			try {
				Class cls = ClassLoaderUtil.loadClass(cname, this.getClass());
				ConfigurationProvider prov = (ConfigurationProvider)cls.newInstance();
				configurationManager.addContainerProvider(prov);
			} catch (InstantiationException e) {
				throw new ConfigurationException("Unable to instantiate provider: "+cname, e);
			} catch (IllegalAccessException e) {
				throw new ConfigurationException("Unable to access provider: "+cname, e);
			} catch (ClassNotFoundException e) {
				throw new ConfigurationException("Unable to locate provider class: "+cname, e);
			}
		}
	}
}

// configurationManager添加ConfigurationProvider,用于获取filter中initParams配置的所有键值对
 private void init_FilterInitParameters() {
	configurationManager.addContainerProvider(new ConfigurationProvider() {
		public void destroy() {
		}

		public void init(Configuration configuration) throws ConfigurationException {
		}

		public void loadPackages() throws ConfigurationException {
		}

		public boolean needsReload() {
			return false;
		}

		public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
			props.putAll(initParams);
		}
	});
}
// configurationManager添加DefaultBeanSelectionProvider,用于创建bean factory,以及关联别名
private void init_AliasStandardObjects() {
	configurationManager.addContainerProvider(new DefaultBeanSelectionProvider());
}

// 创建container,解析struts.xml、struts.properties等配置文件
private Container init_PreloadConfiguration() {
	Container container = getContainer();

	boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));
	LocalizedTextUtil.setReloadBundles(reloadi18n);

	boolean devMode = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_DEVMODE));
	LocalizedTextUtil.setDevMode(devMode);

	return container;
}

public Container getContainer() {
	// 先查看ContainerHolder的ThreadLocal<Container> instance缓存
	if (ContainerHolder.get() != null) {
		return ContainerHolder.get();
	}
	ConfigurationManager mgr = getConfigurationManager();
	if (mgr == null) {
		throw new IllegalStateException("The configuration manager shouldn't be null");
	} else {
		// 获取struts.xml、struts.properties等配置文件解析后的Configuration配置
		Configuration config = mgr.getConfiguration();
		if (config == null) {
			throw new IllegalStateException("Unable to load configuration");
		} else {
			Container container = config.getContainer();
			// 缓存container到ContainerHolder
			ContainerHolder.store(container);
			return container;
		}
	}
}

public ConfigurationManager getConfigurationManager() {
	return configurationManager;
}

/** ConfigurationManager.java */
public synchronized Configuration getConfiguration() {
	if (configuration == null) {
		// 创建DefaultConfiguration
		setConfiguration(createConfiguration(defaultFrameworkBeanName));
		try {
			// 利用ConfigurationManager中的ContainerProviders加载Container
			configuration.reloadContainer(getContainerProviders());
		} catch (ConfigurationException e) {
			setConfiguration(null);
			throw new ConfigurationException("Unable to load configuration.", e);
		}
	} else {
		conditionalReload();
	}

	return configuration;
}

protected Configuration createConfiguration(String beanName) {
	return new DefaultConfiguration(beanName);
}

// 获取ConfigurationManager中的ContainerProviders
public List<ContainerProvider> getContainerProviders() {
	providerLock.lock();
	try {
		if (containerProviders.size() == 0) {
			containerProviders.add(new XWorkConfigurationProvider());
			containerProviders.add(new XmlConfigurationProvider("xwork.xml", false));
		}

		return containerProviders;
	} finally {
		providerLock.unlock();
	}
}

/** DefaultConfiguration.java */
public synchronized List<PackageProvider> reloadContainer(List<ContainerProvider> providers) throws ConfigurationException {
	// 先清空配置缓存
	packageContexts.clear();
	loadedFileNames.clear();
	List<PackageProvider> packageProviders = new ArrayList<PackageProvider>();

	ContainerProperties props = new ContainerProperties();
	ContainerBuilder builder = new ContainerBuilder();
	// 构建ContainerImpl,完成singletonFactories中单例的实例化
	Container bootstrap = createBootstrapContainer(providers);
	for (final ContainerProvider containerProvider : providers)
	{
		bootstrap.inject(containerProvider);
		containerProvider.init(this);
		// 初步解析struts.properties、struts.xml等配置文件
		containerProvider.register(builder, props);
	}
	// 缓存Constants factories
	props.setConstants(builder);

	// builder缓存Configuration.class factory
	builder.factory(Configuration.class, new Factory<Configuration>() {
		public Configuration create(Context context) throws Exception {
			return DefaultConfiguration.this;
		}
	});

	ActionContext oldContext = ActionContext.getContext();
	try {
		// Set the bootstrap container for the purposes of factory creation
		// 创建ActionContext
		setContext(bootstrap);
		// 用初步解析struts.properties、struts.xml等配置文件的builder创建container
		container = builder.create(false);
		setContext(container);
		objectFactory = container.getInstance(ObjectFactory.class);

		// Process the configuration providers first
		for (final ContainerProvider containerProvider : providers)
		{
			if (containerProvider instanceof PackageProvider) {
				// 依赖注入
				container.inject(containerProvider);
				// 具体解析<package>,解析到DefaultConfiguration的Map<String, PackageConfig> packageContexts中
				((PackageProvider)containerProvider).loadPackages();
				packageProviders.add((PackageProvider)containerProvider);
			}
		}

		// Then process any package providers from the plugins
		Set<String> packageProviderNames = container.getInstanceNames(PackageProvider.class);
		for (String name : packageProviderNames) {
			PackageProvider provider = container.getInstance(PackageProvider.class, name);
			provider.init(this);
			provider.loadPackages();
			packageProviders.add(provider);
		}

		// 获取运行时的ActionConfig,其整合了packageConfig、actionConfig
		rebuildRuntimeConfiguration();
	} finally {
		if (oldContext == null) {
			ActionContext.setContext(null);
		}
	}
	return packageProviders;
}

protected Container createBootstrapContainer(List<ContainerProvider> providers) {
	// 临时ContainerBuilder
	ContainerBuilder builder = new ContainerBuilder();
	boolean fmFactoryRegistered = false;
	// ContainerBuilder添加factories、singletonFactories缓存
	for (ContainerProvider provider : providers) {
		if (provider instanceof FileManagerProvider) {
			provider.register(builder, null);
		}
		if (provider instanceof FileManagerFactoryProvider) {
			provider.register(builder, null);
			fmFactoryRegistered = true;
		}
	}
	builder.factory(ObjectFactory.class, Scope.SINGLETON);
	builder.factory(ActionFactory.class, DefaultActionFactory.class, Scope.SINGLETON);
	builder.factory(ResultFactory.class, DefaultResultFactory.class, Scope.SINGLETON);
	builder.factory(InterceptorFactory.class, DefaultInterceptorFactory.class, Scope.SINGLETON);
	builder.factory(com.opensymphony.xwork2.factory.ValidatorFactory.class, com.opensymphony.xwork2.factory.DefaultValidatorFactory.class, Scope.SINGLETON);
	builder.factory(ConverterFactory.class, DefaultConverterFactory.class, Scope.SINGLETON);
	builder.factory(UnknownHandlerFactory.class, DefaultUnknownHandlerFactory.class, Scope.SINGLETON);

	builder.factory(FileManager.class, "system", DefaultFileManager.class, Scope.SINGLETON);
	if (!fmFactoryRegistered) {
		builder.factory(FileManagerFactory.class, DefaultFileManagerFactory.class, Scope.SINGLETON);
	}
	builder.factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON);
	builder.factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON);

	builder.factory(XWorkConverter.class, Scope.SINGLETON);
	builder.factory(ConversionPropertiesProcessor.class, DefaultConversionPropertiesProcessor.class, Scope.SINGLETON);
	builder.factory(ConversionFileProcessor.class, DefaultConversionFileProcessor.class, Scope.SINGLETON);
	builder.factory(ConversionAnnotationProcessor.class, DefaultConversionAnnotationProcessor.class, Scope.SINGLETON);
	builder.factory(TypeConverterCreator.class, DefaultTypeConverterCreator.class, Scope.SINGLETON);
	builder.factory(TypeConverterHolder.class, DefaultTypeConverterHolder.class, Scope.SINGLETON);

	builder.factory(XWorkBasicConverter.class, Scope.SINGLETON);
	builder.factory(TypeConverter.class, XWorkConstants.COLLECTION_CONVERTER,  CollectionConverter.class, Scope.SINGLETON);
	builder.factory(TypeConverter.class, XWorkConstants.ARRAY_CONVERTER, ArrayConverter.class, Scope.SINGLETON);
	builder.factory(TypeConverter.class, XWorkConstants.DATE_CONVERTER, DateConverter.class, Scope.SINGLETON);
	builder.factory(TypeConverter.class, XWorkConstants.NUMBER_CONVERTER,  NumberConverter.class, Scope.SINGLETON);
	builder.factory(TypeConverter.class, XWorkConstants.STRING_CONVERTER, StringConverter.class, Scope.SINGLETON);

	builder.factory(TextParser.class, OgnlTextParser.class, Scope.SINGLETON);
	builder.factory(TextProvider.class, "system", DefaultTextProvider.class, Scope.SINGLETON);

	builder.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON);
	builder.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON);
	builder.factory(OgnlUtil.class, Scope.SINGLETON);

	builder.constant(XWorkConstants.DEV_MODE, "false");
	builder.constant(XWorkConstants.LOG_MISSING_PROPERTIES, "false");
	builder.constant(XWorkConstants.ENABLE_OGNL_EVAL_EXPRESSION, "false");
	builder.constant(XWorkConstants.ENABLE_OGNL_EXPRESSION_CACHE, "true");
	builder.constant(XWorkConstants.RELOAD_XML_CONFIGURATION, "false");

	// 构建ContainerImpl
	return builder.create(true);
}

/** ContainerBuilder.java */
public Container create(boolean loadSingletons) {
	ensureNotCreated();
	created = true;
	// 带factories参数构建ContainerImpl
	final ContainerImpl container = new ContainerImpl(
		new HashMap<Key<?>, InternalFactory<?>>(factories));
	// singletonFactorie单例实例化
	if (loadSingletons) {
	  container.callInContext(new ContainerImpl.ContextualCallable<Void>() {
		public Void call(InternalContext context) {
		  for (InternalFactory<?> factory : singletonFactories) {
			factory.create(context);
		  }
		  return null;
		}
	  });
	}
	container.injectStatics(staticInjections);
	return container;
}

/** ContainerImpl.java */
<T> T callInContext( ContextualCallable<T> callable ) {
	Object[] reference = localContext.get();
	if (reference[0] == null) {
		// new InternalContext(this),创建InternalContext环境
		reference[0] = new InternalContext(this);
		try {
			// 调用callable
			return callable.call((InternalContext) reference[0]);
		} finally {
			// Only remove the context if this call created it.
			reference[0] = null;
			// WW-3768: ThreadLocal was not removed
			localContext.remove();
		}
	} else {
		// Someone else will clean up this context.
		return callable.call((InternalContext) reference[0]);
	}
}

/** DefaultConfiguration.java */
protected ActionContext setContext(Container cont) {
	ActionContext context = ActionContext.getContext();
	if (context == null) {
		// 创建ValueStack
		ValueStack vs = cont.getInstance(ValueStackFactory.class).createValueStack();
		// 创建ActionContext
		context = new ActionContext(vs.getContext());
		ActionContext.setContext(context);
	}
	return context;
}

/** DefaultDispatcherErrorHandler.java */
public void init(ServletContext ctx) {
	try {
		freemarker.template.Configuration config = freemarkerManager.getConfiguration(ctx);
		template = config.getTemplate("/org/apache/struts2/dispatcher/error.ftl");
	} catch (IOException e) {
		throw new StrutsException(e);
	}
}

/** InitOperations.java */
public StaticContentLoader initStaticContentLoader( HostConfig filterConfig, Dispatcher dispatcher ) {
	StaticContentLoader loader = dispatcher.getContainer().getInstance(StaticContentLoader.class);
	loader.setHostConfig(filterConfig);
	return loader;
}

一次http请求处理流程

调用栈


整体流程

一次http请求处理流程:


DefaultActionProxyFactory创建createActionProxy:


ActionInvocation类结构图:


相关源码

/** StrutsPrepareAndExecuteFilter.java */
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

	HttpServletRequest request = (HttpServletRequest) req;
	HttpServletResponse response = (HttpServletResponse) res;

	try {
		if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
			chain.doFilter(request, response);
		} else {
			// 设置request CharacterEncoding为UTF-8;设置response Locale(zh_CN)
			prepare.setEncodingAndLocale(request, response);
			// 创建ActionContext
			prepare.createActionContext(request, response);
			// 单例缓存dispatcher
			prepare.assignDispatcherToThread();
			// wrap request
			request = prepare.wrapRequest(request);
			// 根据请求url,创建ActionMapping
			ActionMapping mapping = prepare.findActionMapping(request, response, true);
			if (mapping == null) {
				boolean handled = execute.executeStaticResourceRequest(request, response);
				if (!handled) {
					chain.doFilter(request, response);
				}
			} else {
				// 真正处理http请求
				execute.executeAction(request, response, mapping);
			}
		}
	} finally {
		// ActionContext\Dispatcher\ContainerHolder单例缓存清空
		prepare.cleanupRequest(request);
	}
}

/** PrepareOperations.java */
public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
	ActionContext ctx;
	Integer counter = 1;
	Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
	if (oldCounter != null) {
		counter = oldCounter + 1;
	}
	
	ActionContext oldContext = ActionContext.getContext();
	// 创建ActionContext
	if (oldContext != null) {
		// detected existing context, so we are probably in a forward
		ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));
	} else {
		ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
		stack.getContext().putAll(dispatcher.createContextMap(request, response, null));
		ctx = new ActionContext(stack.getContext());
	}
	request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
	// 单例缓存ActionContext
	ActionContext.setContext(ctx);
	return ctx;
}

public void assignDispatcherToThread() {
	Dispatcher.setInstance(dispatcher);
}

public HttpServletRequest wrapRequest(HttpServletRequest oldRequest) throws ServletException {
	HttpServletRequest request = oldRequest;
	try {
		// Wrap request first, just in case it is multipart/form-data
		// parameters might not be accessible through before encoding (ww-1278)
		request = dispatcher.wrapRequest(request);
	} catch (IOException e) {
		throw new ServletException("Could not wrap servlet request with MultipartRequestWrapper!", e);
	}
	return request;
}

public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup) {
	ActionMapping mapping = (ActionMapping) request.getAttribute(STRUTS_ACTION_MAPPING_KEY);
	if (mapping == null || forceLookup) {
		try {
			// 根据请求url,创建ActionMapping
			mapping = dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager());
			if (mapping != null) {
				// 设置request属性struts.actionMapping为mapping
				request.setAttribute(STRUTS_ACTION_MAPPING_KEY, mapping);
			}
		} catch (Exception ex) {
			dispatcher.sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
		}
	}

	return mapping;
}

/** Dispatcher.java */
// wrap Request,主要分清文件请求还是一般请求
public HttpServletRequest wrapRequest(HttpServletRequest request) throws IOException {
	// don't wrap more than once
	if (request instanceof StrutsRequestWrapper) {
		return request;
	}

	String content_type = request.getContentType();
	if (content_type != null && content_type.contains("multipart/form-data")) {
		// 文件上传
		MultiPartRequest mpr = getMultiPartRequest();
		LocaleProvider provider = getContainer().getInstance(LocaleProvider.class);
		request = new MultiPartRequestWrapper(mpr, request, getSaveDir(), provider, disableRequestAttributeValueStackLookup);
	} else {
		// 一般请求
		request = new StrutsRequestWrapper(request, disableRequestAttributeValueStackLookup);
	}

	return request;
}

/** DefaultActionMapper.java */
 public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) {
	ActionMapping mapping = new ActionMapping();
	// 获取请求url
	String uri = RequestUtils.getUri(request);

	int indexOfSemicolon = uri.indexOf(";");
	uri = (indexOfSemicolon > -1) ? uri.substring(0, indexOfSemicolon) : uri;

	// 去掉uri中的.action后缀
	uri = dropExtension(uri, mapping);
	if (uri == null) {
		return null;
	}
	// 解析请求url中的Namespace和action name
	parseNameAndNamespace(uri, mapping, configManager);
	handleSpecialParameters(request, mapping);
	return parseActionName(mapping);
}

/** ExecuteOperations.java */
public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
	// 处理请求工作委托给dispatcher
	dispatcher.serviceAction(request, response, mapping);
}

/** Dispatcher.java */
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping)
		throws ServletException {

	// 创建属性Map,包括request、session、application等范围的属性及其他属性
	Map<String, Object> extraContext = createContextMap(request, response, mapping);

	// 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添加ValueStack属性
		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();
		
		// 创建ActionProxy
		ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
				namespace, name, method, extraContext, true, false);
		
		// request设置struts.valueStack属性
		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 {
			// 处理http请求
			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) {
		logConfigurationException(request, e);
		sendError(request, response, HttpServletResponse.SC_NOT_FOUND, e);
	} catch (Exception e) {
		if (handleException || devMode) {
			sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
		} else {
			throw new ServletException(e);
		}
	} finally {
		UtilTimerStack.pop(timerKey);
	}
}

/** DefaultActionProxy.java */
protected void prepare() {
	String profileKey = "create DefaultActionProxy: ";
	try {
		UtilTimerStack.push(profileKey);
		// 根据namespace、actionName获取Runtime ActionConfig
		config = configuration.getRuntimeConfiguration().getActionConfig(namespace, actionName);

		if (config == null && unknownHandlerManager.hasUnknownHandlers()) {
			config = unknownHandlerManager.handleUnknownAction(namespace, actionName);
		}
		if (config == null) {
			throw new ConfigurationException(getErrorMessage());
		}
		
		// 确定执行action的哪个method
		resolveMethod();

		if (!config.isAllowedMethod(method)) {
			throw new ConfigurationException("Invalid method: " + method + " for action " + actionName);
		}
		
		// DefaultActionInvocation init
		invocation.init(this);

	} finally {
		UtilTimerStack.pop(profileKey);
	}
}

/** DefaultActionInvocation.java */
public void init(ActionProxy proxy) {
	this.proxy = proxy;
	Map<String, Object> contextMap = createContextMap();

	// Setting this so that other classes, like object factories, can use the ActionProxy and other
	// contextual information to operate
	ActionContext actionContext = ActionContext.getContext();

	// 将DefaultActionInvocation actionInvocation put到actionContext
	if (actionContext != null) {
		actionContext.setActionInvocation(this);
	}

	// 在DefaultActionInvocation中,实例化action对象,且完成依赖注入
	createAction(contextMap);

	if (pushAction) {
		// 将action对象push到ValueStack
		stack.push(action); 
		// OgnlContext put action对象
		contextMap.put("action", action);
	}

	// 用OgnlContext创建ActionContext
	invocationContext = new ActionContext(contextMap);
	// 用actionName设置invocationContext名称
	invocationContext.setName(proxy.getActionName());

	// get a new List so we don't get problems with the iterator if someone changes the list
	// new interceptorList
	List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors());
	interceptors = interceptorList.iterator();
}

protected Map<String, Object> createContextMap() {
	Map<String, Object> contextMap;

	if ((extraContext != null) && (extraContext.containsKey(ActionContext.VALUE_STACK))) {
		// 从extraContext中获取ValueStack
		stack = (ValueStack) extraContext.get(ActionContext.VALUE_STACK);

		if (stack == null) {
			throw new IllegalStateException("There was a null Stack set into the extra params.");
		}
		// 获取ValueStack的OgnlContext
		contextMap = stack.getContext();
	} else {
		// create the value stack
		// this also adds the ValueStack to its context
		stack = valueStackFactory.createValueStack();

		// create the action context
		contextMap = stack.getContext();
	}

	// 将extraContext中的key-value对put到ValueStack的OgnlContext
	if (extraContext != null) {
		contextMap.putAll(extraContext);
	}

	// contextMap put DefaultActionInvocation actionInvocation属性
	contextMap.put(ActionContext.ACTION_INVOCATION, this);
	// contextMap put container属性
	contextMap.put(ActionContext.CONTAINER, container);

	return contextMap;
}

protected void createAction(Map<String, Object> contextMap) {
	// load action
	String timerKey = "actionCreate: " + proxy.getActionName();
	try {
		UtilTimerStack.push(timerKey);
		// 实例化action对象,且完成依赖注入
		action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);
	} catch (InstantiationException e) {
		throw new XWorkException("Unable to intantiate Action!", e, proxy.getConfig());
	} catch (IllegalAccessException e) {
		throw new XWorkException("Illegal access to constructor, is it public?", e, proxy.getConfig());
	} catch (Exception e) {
		String gripe;

		if (proxy == null) {	
			gripe = "Whoa!  No ActionProxy instance found in current ActionInvocation.  This is bad ... very bad";
		} else if (proxy.getConfig() == null) {
			gripe = "Sheesh.  Where'd that ActionProxy get to?  I can't find it in the current ActionInvocation!?";
		} else if (proxy.getConfig().getClassName() == null) {
			gripe = "No Action defined for '" + proxy.getActionName() + "' in namespace '" + proxy.getNamespace() + "'";
		} else {
			gripe = "Unable to instantiate Action, " + proxy.getConfig().getClassName() + ",  defined for '" + proxy.getActionName() + "' in namespace '" + proxy.getNamespace() + "'";
		}

		gripe += (((" -- " + e.getMessage()) != null) ? e.getMessage() : " [no message in exception]");
		throw new XWorkException(gripe, e, proxy.getConfig());
	} finally {
		UtilTimerStack.pop(timerKey);
	}

	if (actionEventListener != null) {
		action = actionEventListener.prepare(action, stack);
	}
}

/** ObjectFactory.java */
public Object buildAction(String actionName, String namespace, ActionConfig config, Map<String, Object> extraContext) throws Exception {
	return actionFactory.buildAction(actionName, namespace, config, extraContext);
}

/** DefaultActionFactory.java */
// 实例化action对象的工作委托给objectFactory
public Object buildAction(String actionName, String namespace, ActionConfig config, Map<String, Object> extraContext) throws Exception {
	return objectFactory.buildBean(config.getClassName(), extraContext);
}

/** ObjectFactory.java */
public Object buildBean(String className, Map<String, Object> extraContext) throws Exception {
	return buildBean(className, extraContext, true);
}

// 实例化action对象,且完成依赖注入
public Object buildBean(String className, Map<String, Object> extraContext, boolean injectInternal) throws Exception {
	// 加载Class
	Class clazz = getClassInstance(className);
	// 用反射实例化action对象
	Object obj = buildBean(clazz, extraContext);
	if (injectInternal) {
		// 对action对象进行依赖注入
		injectInternalBeans(obj);
	}
	return obj;
}

public Object buildBean(Class clazz, Map<String, Object> extraContext) throws Exception {
	return clazz.newInstance();
}

protected Object injectInternalBeans(Object obj) {
	if (obj != null && container != null) {
		container.inject(obj);
	}
	return obj;
}

/** StrutsActionProxy.java */
public String execute() throws Exception {
	ActionContext previous = ActionContext.getContext();
	// 将DefaultActionInvocation的ActionContext设置为当前线程的ActionContext
	ActionContext.setContext(invocation.getInvocationContext());
	try {
		// DefaultActionInvocation调用
		return invocation.invoke();
	} finally {
		if (cleanupContext)
			ActionContext.setContext(previous);
	}
}

/** DefaultActionInvocation.java */
public String invoke() throws Exception {
	String profileKey = "invoke: ";
	try {
		UtilTimerStack.push(profileKey);

		if (executed) {
			throw new IllegalStateException("Action has already executed");
		}
		
		// 执行interceptor链
		if (interceptors.hasNext()) {
			final InterceptorMapping interceptor = interceptors.next();
			String interceptorMsg = "interceptor: " + interceptor.getName();
			UtilTimerStack.push(interceptorMsg);
			try {
							resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
						}
			finally {
				UtilTimerStack.pop(interceptorMsg);
			}
		} else {
			// 执行http请求对应的action
			resultCode = invokeActionOnly();
		}

		// this is needed because the result will be executed, then control will return to the Interceptor, which will
		// return above and flow through again
		if (!executed) {
			if (preResultListeners != null) {
				for (Object preResultListener : preResultListeners) {
					PreResultListener listener = (PreResultListener) preResultListener;

					String _profileKey = "preResultListener: ";
					try {
						UtilTimerStack.push(_profileKey);
						listener.beforeResult(this, resultCode);
					}
					finally {
						UtilTimerStack.pop(_profileKey);
					}
				}
			}

			// now execute the result, if we're supposed to
			if (proxy.getExecuteResult()) {
				// 在ServletDispatcherResult中,根据result finalLocation获取RequestDispatcher,进行页面跳转
				// 本质上是设置HttpServletResponse返回的内容,后续interceptor链还可以修改HttpServletResponse的内容
				executeResult();
			}

			executed = true;
		}

		return resultCode;
	}
	finally {
		UtilTimerStack.pop(profileKey);
	}
}

public String invokeActionOnly() throws Exception {
	return invokeAction(getAction(), proxy.getConfig());
}

protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
	String methodName = proxy.getMethod();

	if (LOG.isDebugEnabled()) {
		LOG.debug("Executing action method = #0", methodName);
	}

	String timerKey = "invokeAction: " + proxy.getActionName();
	try {
		UtilTimerStack.push(timerKey);

		Object methodResult;
		try {
			// ognl利用反射执行method,获取methodResult
			methodResult = ognlUtil.getValue(methodName + "()", getStack().getContext(), action);
		} catch (MethodFailedException e) {
			// if reason is missing method, try find version with "do" prefix
			if (e.getReason() instanceof NoSuchMethodException) {
				try {
					String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1) + "()";
					methodResult = ognlUtil.getValue(altMethodName, getStack().getContext(), action);
				} catch (MethodFailedException e1) {
					// if still method doesn't exist, try checking UnknownHandlers
					if (e1.getReason() instanceof NoSuchMethodException) {
						if (unknownHandlerManager.hasUnknownHandlers()) {
							try {
								methodResult = unknownHandlerManager.handleUnknownMethod(action, methodName);
							} catch (NoSuchMethodException e2) {
								// throw the original one
								throw e;
							}
						} else {
							// throw the original one
							throw e;
						}
						// throw the original exception as UnknownHandlers weren't able to handle invocation as well
						if (methodResult == null) {
							throw e;
						}
					} else {
						// exception isn't related to missing action method, throw it
						throw e1;
					}
				}
			} else {
				// exception isn't related to missing action method, throw it
				throw e;
			}
		}
		return saveResult(actionConfig, methodResult);
	} catch (NoSuchPropertyException e) {
		throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");
	} catch (MethodFailedException e) {
		// We try to return the source exception.
		Throwable t = e.getCause();

		if (actionEventListener != null) {
			String result = actionEventListener.handleException(t, getStack());
			if (result != null) {
				return result;
			}
		}
		if (t instanceof Exception) {
			throw (Exception) t;
		} else {
			throw e;
		}
	} finally {
		UtilTimerStack.pop(timerKey);
	}
}

/** OgnlUtil.java */
 public Object getValue(final String name, final Map<String, Object> context, final Object root) throws OgnlException {
	return compileAndExecute(name, context, new OgnlTask<Object>() {
		public Object execute(Object tree) throws OgnlException {
			return Ognl.getValue(tree, context, root);
		}
	});
}

private <T> Object compileAndExecute(String expression, Map<String, Object> context, OgnlTask<T> task) throws OgnlException {
	Object tree;
	if (enableExpressionCache) {
		tree = expressions.get(expression);
		if (tree == null) {
			tree = Ognl.parseExpression(expression);
			checkEnableEvalExpression(tree, context);
		}
	} else {
		tree = Ognl.parseExpression(expression);
		checkEnableEvalExpression(tree, context);
	}
	
	// ognl利用反射执行method
	final T exec = task.execute(tree);
	// if cache is enabled and it's a valid expression, puts it in
	if(enableExpressionCache) {
		expressions.putIfAbsent(expression, tree);
	}
	return exec;
}

/** DefaultActionInvocation.java */
private void executeResult() throws Exception {
	// 获取action执行的ServletDispatcherResult
	result = createResult();

	String timerKey = "executeResult: " + getResultCode();
	try {
		UtilTimerStack.push(timerKey);
		if (result != null) {
			result.execute(this);
		} else if (resultCode != null && !Action.NONE.equals(resultCode)) {
			throw new ConfigurationException("No result defined for action " + getAction().getClass().getName()
					+ " and result " + getResultCode(), proxy.getConfig());
		} else {
			if (LOG.isDebugEnabled()) {
				LOG.debug("No result returned for action " + getAction().getClass().getName() + " at " + proxy.getConfig().getLocation());
			}
		}
	} finally {
		UtilTimerStack.pop(timerKey);
	}
}

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();

	ResultConfig resultConfig = null;

	try {
		resultConfig = results.get(resultCode);
	} catch (NullPointerException e) {
		if (LOG.isDebugEnabled()) {
			LOG.debug("Got NPE trying to read result configuration for resultCode [#0]", resultCode);
		}
	}
	
	if (resultConfig == null) {
		// If no result is found for the given resultCode, try to get a wildcard '*' match.
		resultConfig = results.get("*");
	}

	if (resultConfig != null) {
		try {
			// new ServletDispatcherResult对象
			return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());
		} catch (Exception e) {
			if (LOG.isErrorEnabled()) {
				LOG.error("There was an exception while instantiating the result of type #0", e, resultConfig.getClassName());
			}
			throw new XWorkException(e, resultConfig);
		}
	} else if (resultCode != null && !Action.NONE.equals(resultCode) && unknownHandlerManager.hasUnknownHandlers()) {
		return unknownHandlerManager.handleUnknownResult(invocationContext, proxy.getActionName(), proxy.getConfig(), resultCode);
	}
	return null;
}

/** ObjectFactory.java */
 public Result buildResult(ResultConfig resultConfig, Map<String, Object> extraContext) throws Exception {
	return resultFactory.buildResult(resultConfig, extraContext);
}

/** StrutsResultFactory.java */
public Result buildResult(ResultConfig resultConfig, Map<String, Object> extraContext) throws Exception {
	String resultClassName = resultConfig.getClassName();
	Result result = null;

	if (resultClassName != null) {
		// new ServletDispatcherResult对象
		result = (Result) objectFactory.buildBean(resultClassName, extraContext);
		Map<String, String> params = resultConfig.getParams();
		if (params != null) {
			setParameters(extraContext, result, params);
		}
	}
	return result;
}

protected void setParameters(Map<String, Object> extraContext, Result result, Map<String, String> params) {
	for (Map.Entry<String, String> paramEntry : params.entrySet()) {
		try {
			String name = paramEntry.getKey();
			String value = paramEntry.getValue();
			// ognl设置key-value
			setParameter(result, name, value, extraContext);
		} catch (ReflectionException ex) {
			if (result instanceof ReflectionExceptionHandler) {
				((ReflectionExceptionHandler) result).handle(ex);
			}
		}
	}
}

protected void setParameter(Result result, String name, String value, Map<String, Object> extraContext) {
	if (result instanceof ParamNameAwareResult) {
		if (((ParamNameAwareResult) result).acceptableParameterName(name, value)) {
			reflectionProvider.setProperty(name, value, result, extraContext, true);
		}
	} else {
		reflectionProvider.setProperty(name, value, result, extraContext, true);
	}
}

/** StrutsResultSupport.java */
public void execute(ActionInvocation invocation) throws Exception {
	lastFinalLocation = conditionalParse(location, invocation);
	doExecute(lastFinalLocation, invocation);
}

/** ServletDispatcherResult.java */
public void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
	if (LOG.isDebugEnabled()) {
		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();
		// 根据result finalLocation获取RequestDispatcher,用于页面跳转
		RequestDispatcher dispatcher = request.getRequestDispatcher(finalLocation);

		//add parameters passed on the location to #parameters
		// see WW-2120
		if (StringUtils.isNotEmpty(finalLocation) && finalLocation.indexOf("?") > 0) {
			String queryString = finalLocation.substring(finalLocation.indexOf("?") + 1);
			Map<String, Object> parameters = getParameters(invocation);
			Map<String, Object> queryParams = urlHelper.parseQueryString(queryString, true);
			if (queryParams != null && !queryParams.isEmpty())
				parameters.putAll(queryParams);
		}

		// if the view doesn't exist, let's do a 404
		if (dispatcher == null) {
			response.sendError(404, "result '" + finalLocation + "' not found");
			return;
		}

		//if we are inside an action tag, we always need to do an include
		Boolean insideActionTag = (Boolean) ObjectUtils.defaultIfNull(request.getAttribute(StrutsStatics.STRUTS_ACTION_TAG_INVOCATION), Boolean.FALSE);

		// If we're included, then include the view
		// Otherwise do forward
		// This allow the page to, for example, set content type
		if (!insideActionTag && !response.isCommitted() && (request.getAttribute("javax.servlet.include.servlet_path") == null)) {
			// 设置request struts.view_uri、struts.request_uri属性
			request.setAttribute("struts.view_uri", finalLocation);
			request.setAttribute("struts.request_uri", request.getRequestURI());

			dispatcher.forward(request, response);
		} else {
			dispatcher.include(request, response);
		}
	}
}

       通过源码分析,进一步了解Struts2的基本架构。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值