Dispatcher也叫做核心分发器,Dispatcher类负责整个Struts2项目的初始化工作。这是一个很庞大的类,这里会挑选一些重要的方法进行分析。
很明显这是一个应用ThreadLocal的例子,它为当前线程中的一个叫做ThreadLocalMap的线程副本,使得线程与线程之间,每一个线程可以独立的修改自己的副本,而不会影响到其他线程的变量,从而使线程安全。
Dispatcher分发器的出现,作用是由刚刚处理过Http请求,并完成初始化后的struts2部分转入xwork部分。
private static ThreadLocal<Dispatcher> instance = new ThreadLocal<Dispatcher>();
初始化国际化方法
@Inject(value=StrutsConstants.STRUTS_LOCALE, required=false)
public void setDefaultLocale(String val) {
defaultLocale = val;
}
@Inject(StrutsConstants.STRUTS_I18N_ENCODING)
public void setDefaultEncoding(String val) {
defaultEncoding = val;
}
cleanup()方法,清除当前线程之中的对象实例,清空拦截器栈等。
public void cleanup() {
// clean up ObjectFactory
//清除对象实例
ObjectFactory objectFactory = getContainer().getInstance(ObjectFactory.class);
if (objectFactory == null) {
if (LOG.isWarnEnabled()) {
LOG.warn("Object Factory is null, something is seriously wrong, no clean up will be performed");
}
}
if (objectFactory instanceof ObjectFactoryDestroyable) {
try {
((ObjectFactoryDestroyable)objectFactory).destroy();
}
catch(Exception e) {
// catch any exception that may occurred during destroy() and log it
LOG.error("exception occurred while destroying ObjectFactory [#0]", e, objectFactory.toString());
}
}
//将当前分发器的引用置为null
instance.set(null);
//销毁Dispatcher监听器
if (!dispatcherListeners.isEmpty()) {
for (DispatcherListener l : dispatcherListeners) {
l.dispatcherDestroyed(this);
}
}
// clean up all interceptors by calling their destroy() method
Set<Interceptor> interceptors = new HashSet<Interceptor>();
Collection<PackageConfig> packageConfigs = configurationManager.getConfiguration().getPackageConfigs().values();
for (PackageConfig packageConfig : packageConfigs) {
for (Object config : packageConfig.getAllInterceptorConfigs().values()) {
if (config instanceof InterceptorStackConfig) {
for (InterceptorMapping interceptorMapping : ((InterceptorStackConfig) config).getInterceptors()) {
interceptors.add(interceptorMapping.getInterceptor());
}
}
}
}
//清空拦截器栈
for (Interceptor interceptor : interceptors) {
interceptor.destroy();
}
// Clear container holder when application is unloaded / server shutdown
ContainerHolder.clear();
//销毁ActionContext
ActionContext.setContext(null);
// clean up configuration
configurationManager.destroyConfiguration();
configurationManager = null;
}
Dispatcher最重要的方法就是init(),初始化方法。
public void init() {
//判断ConfigurationManager对象是否为null,如果为null,new一个
if (configurationManager == null) {
configurationManager = createConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
}
try {
//对配置文件进行初始化
init_FileManager();
//default.properties初始化
init_DefaultProperties(); // [1]
//xwork配置文件的初始化
init_TraditionalXmlConfigurations(); // [2]
init_LegacyStrutsProperties(); // [3]
init_CustomConfigurationProviders(); // [5]
init_FilterInitParameters() ; // [6]
init_AliasStandardObjects() ; // [7]
//初始化国际化
Container container = init_PreloadConfiguration();
//注入容器,container
container.inject(this);
init_CheckWebLogicWorkaround(container);
if (!dispatcherListeners.isEmpty()) {
for (DispatcherListener l : dispatcherListeners) {
l.dispatcherInitialized(this);
}
}
} catch (Exception ex) {
if (LOG.isErrorEnabled())
LOG.error("Dispatcher initialization failed", ex);
throw new StrutsException(ex);
}
}
serviceAction()方法,这个方法也是执行action的主要流程的方法
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,
ActionMapping mapping) throws ServletException {
//创建action对应的上下文映射,在我看来是一种封装
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,也就是我们所说的上下文
ActionContext ctx = ActionContext.getContext();
if (ctx != null) {
stack = ctx.getValueStack();
}
}
if (stack != null) {
//将action对应的映射压入值栈
extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));
}
String timerKey = "Handling request from Dispatcher";
try {
UtilTimerStack.push(timerKey);
//获取action的信息,action名,方法等
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!
//拦截器执行完毕后返回的resultCode如果不为null,就执行结果集
if (mapping.getResult() != null) {
Result result = mapping.getResult();
result.execute(proxy.getInvocation());
} else {
//执行完结果集后执行execute()方法
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) {
if (handleException || devMode) {
sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
} else {
throw new ServletException(e);
}
} finally {
UtilTimerStack.pop(timerKey);
}
}
wrapRequest()方法,是对HttpServletRequest 类型的请求进行包装,应用了装饰器模式,目的是将Http服务端与初始化解耦,将其分离
public HttpServletRequest wrapRequest(HttpServletRequest request, ServletContext servletContext) 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(servletContext), provider);
} else {
request = new StrutsRequestWrapper(request, disableRequestAttributeValueStackLookup);
}
return request;
}
createContextMap()方法,创建上下文映射,并将其压栈
public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,
ActionMapping mapping, ServletContext context) {
// request map wrapping the http request objects
Map requestMap = new RequestMap(request);
// parameters map wrapping the http parameters. ActionMapping parameters are now handled and applied separately
Map params = new HashMap(request.getParameterMap());
// session map wrapping the http session
Map session = new SessionMap(request);
// application map wrapping the ServletContext
Map application = new ApplicationMap(context);
Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context);
if (mapping != null) {
extraContext.put(ServletActionContext.ACTION_MAPPING, mapping);
}
return extraContext;
}
其余的方法是对,上传下载,对容器,上下文,值栈的初始化,以及国际化,字符编码的初始化。