Struts2源码分析--请求处理(转)
本文转自 http://www.blogjava.net/myyate/articles/Struts2_source_java.html
Struts2架构图
publicvoidinit(FilterConfigfilterConfig)throwsServletException{
try{
this.filterConfig=filterConfig;
initLogging();
dispatcher=createDispatcher(filterConfig);
dispatcher.init();
dispatcher.getContainer().inject(this);
//读取初始参数pakages,调用parse(),解析成类似/org/apache/struts2/static,/template的数组
Stringparam=filterConfig.getInitParameter("packages");
Stringpackages="org.apache.struts2.statictemplateorg.apache.struts2.interceptor.debugging";
if(param!=null){
packages=param+""+packages;
}
this.pathPrefixes=parse(packages);
}finally{
ActionContext.setContext(null);
}
}configurationManager.addConfigurationProvider(newDefaultPropertiesProvider());
}throwsConfigurationException{
SettingsdefaultSettings=null;
try{
defaultSettings=newPropertiesSettings("org/apache/struts2/default");
}catch(Exceptione){
thrownewConfigurationException("Couldnotfindorerrorinorg/apache/struts2/default.properties",e);
}
loadSettings(props,defaultSettings);
}
//PropertiesSettings
//读取org/apache/struts2/default.properties的配置信息,如果项目中需要覆盖,可以在classpath里的struts.properties里覆写
publicPropertiesSettings(Stringname){
URLsettingsUrl=ClassLoaderUtils.getResource(name+".properties",getClass());
if(settingsUrl==null){
LOG.debug(name+".propertiesmissing");
settings=newLocatableProperties();
return;
}
settings=newLocatableProperties(newLocationImpl(null,settingsUrl.toString()));
//Loadsettings
InputStreamin=null;
try{
in=settingsUrl.openStream();
settings.load(in);
}catch(IOExceptione){
thrownewStrutsException("Couldnotload"+name+".properties:"+e,e);
}finally{
if(in!=null){
try{
in.close();
}catch(IOExceptionio){
LOG.warn("Unabletocloseinputstream",io);
}
}
}
}
//首先读取web.xml中的config初始参数值
//如果没有配置就使用默认的"struts-default.xml,struts-plugin.xml,struts.xml",
//这儿就可以看出为什么默认的配置文件必须取名为这三个名称了
//如果不想使用默认的名称,直接在web.xml中配置config初始参数即可
StringconfigPaths=initParams.get("config");
if(configPaths==null){
configPaths=DEFAULT_CONFIGURATION_PATHS;
}
String[]files=configPaths.split("\\s*[,]\\s*");
//依次解析配置文件,xwork.xml单独解析
for(Stringfile:files){
if(file.endsWith(".xml")){
if("xwork.xml".equals(file)){
configurationManager.addConfigurationProvider(newXmlConfigurationProvider(file,false));
}else{
configurationManager.addConfigurationProvider(newStrutsXmlConfigurationProvider(file,false,servletContext));
}
}else{
thrownewIllegalArgumentException("Invalidconfigurationfilename");
}
}
}PackageConfig.BuildernewPackage=buildPackageContext(packageElement);
if(newPackage.isNeedsRefresh()){
returnnewPackage.build();
}
.
addResultTypes(newPackage,packageElement);
loadInterceptors(newPackage,packageElement);
loadDefaultInterceptorRef(newPackage,packageElement);
loadDefaultClassRef(newPackage,packageElement);
loadGlobalResults(newPackage,packageElement);
loadGobalExceptionMappings(newPackage,packageElement);
NodeListactionList=packageElement.getElementsByTagName("action");
for(inti=0;i<actionList.getLength();i++){
ElementactionElement=(Element)actionList.item(i);
addAction(actionElement,newPackage);
}
loadDefaultActionRef(newPackage,packageElement);
PackageConfigcfg=newPackage.build();
configuration.addPackageConfig(cfg.getName(),cfg);
returncfg;
}List<Document>docs=newArrayList<Document>();
if(!includedFileNames.contains(fileName)){
ElementrootElement=doc.getDocumentElement();
NodeListchildren=rootElement.getChildNodes();
intchildSize=children.getLength();
for(inti=0;i<childSize;i++){
NodechildNode=children.item(i);
if(childNodeinstanceofElement){
Elementchild=(Element)childNode;
finalStringnodeName=child.getNodeName();
//解析每个action配置是,对于include文件可以使用通配符*来进行配置
//如Struts.xml中可配置成<includefile="actions_*.xml"/>
if(nodeName.equals("include")){
StringincludeFileName=child.getAttribute("file");
if(includeFileName.indexOf('*')!=-1){
ClassPathFinderwildcardFinder=newClassPathFinder();
wildcardFinder.setPattern(includeFileName);
Vector<String>wildcardMatches=wildcardFinder.findMatches();
for(Stringmatch:wildcardMatches){
docs.addAll(loadConfigurationFiles(match,child));
}
}
else{
docs.addAll(loadConfigurationFiles(includeFileName,child));
}
}
}
}
docs.add(doc);
loadedFileUrls.add(url.toString());
}
}
returndocs;
}StringconfigProvs=initParams.get("configProviders");
if(configProvs!=null){
String[]classes=configProvs.split("\\s*[,]\\s*");
for(Stringcname:classes){
try{
Classcls=ClassLoaderUtils.loadClass(cname,this.getClass());
ConfigurationProviderprov=(ConfigurationProvider)cls.newInstance();
configurationManager.addConfigurationProvider(prov);
}
}
}
}HttpServletRequestrequest=(HttpServletRequest)req;
HttpServletResponseresponse=(HttpServletResponse)res;
ServletContextservletContext=getServletContext();
StringtimerKey="FilterDispatcher_doFilter:";
try{
ValueStackstack=dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
ActionContextctx=newActionContext(stack.getContext());
ActionContext.setContext(ctx);
UtilTimerStack.push(timerKey);
//根据contenttype来使用不同的Request封装,可以参见Dispatcher的wrapRequest
request=prepareDispatcherAndWrapRequest(request,response);
ActionMappingmapping;
try{
//根据url取得对应的Action的配置信息--ActionMapping,actionMapper是通过Container的inject注入的
mapping=actionMapper.getMapping(request,dispatcher.getConfigurationManager());
}catch(Exceptionex){
log.error("errorgettingActionMapping",ex);
dispatcher.sendError(request,response,servletContext,HttpServletResponse.SC_INTERNAL_SERVER_ERROR,ex);
return;
}
//如果找不到对应的action配置,则直接返回。比如你输入***.jsp等等
//这儿有个例外,就是如果path是以“/struts”开头,则到初始参数packages配置的包路径去查找对应的静态资源并输出到页面流中,当然.class文件除外。如果再没有则跳转到404
if(mapping==null){
//thereisnoactioninthisrequest,shouldwelookforastaticresource?
StringresourcePath=RequestUtils.getServletPath(request);
if("".equals(resourcePath)&&null!=request.getPathInfo()){
resourcePath=request.getPathInfo();
}
if(serveStatic&&resourcePath.startsWith("/struts")){
Stringname=resourcePath.substring("/struts".length());
findStaticResource(name,request,response);
}else{
chain.doFilter(request,response);
}
return;
}
//正式开始Action的方法了
dispatcher.serviceAction(request,response,servletContext,mapping);
}finally{
try{
ActionContextCleanUp.cleanUp(req);
}finally{
UtilTimerStack.pop(timerKey);
}
}
}Map<String,Object>extraContext=createContextMap(request,response,mapping,context);
//Iftherewasapreviousvaluestack,thencreateanewcopyandpassitintobeusedbythenewAction
ValueStackstack=(ValueStack)request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
if(stack!=null){
extraContext.put(ActionContext.VALUE_STACK,valueStackFactory.createValueStack(stack));
}
StringtimerKey="HandlingrequestfromDispatcher";
try{
UtilTimerStack.push(timerKey);
Stringnamespace=mapping.getNamespace();
Stringname=mapping.getName();
Stringmethod=mapping.getMethod();
Configurationconfig=configurationManager.getConfiguration();
ActionProxyproxy=config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
namespace,name,method,extraContext,true,false);
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY,proxy.getInvocation().getStack());
//iftheActionMappingsaystogostraighttoaresult,doit!
if(mapping.getResult()!=null){
Resultresult=mapping.getResult();
result.execute(proxy.getInvocation());
}else{
proxy.execute();
}
//Iftherewasapreviousvaluestackthensetitbackontotherequest
if(stack!=null){
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY,stack);
}
}catch(ConfigurationExceptione){
LOG.error("Couldnotfindactionorresult",e);
sendError(request,response,context,HttpServletResponse.SC_NOT_FOUND,e);
}catch(Exceptione){
sendError(request,response,context,HttpServletResponse.SC_INTERNAL_SERVER_ERROR,e);
}finally{
UtilTimerStack.pop(timerKey);
}
}ActionMappingmapping,ServletContextcontext){
//requestmapwrappingthehttprequestobjects
MaprequestMap=newRequestMap(request);
//parametersmapwrappingthehttpparameters.ActionMappingparametersarenowhandledandappliedseparately
Mapparams=newHashMap(request.getParameterMap());
//sessionmapwrappingthehttpsession
Mapsession=newSessionMap(request);
//applicationmapwrappingtheServletContext
Mapapplication=newApplicationMap(context);
Map<String,Object>extraContext=createContextMap(requestMap,params,session,application,request,response,context);
extraContext.put(ServletActionContext.ACTION_MAPPING,mapping);
returnextraContext;
}this.proxy=proxy;
MapcontextMap=createContextMap();
//Settingthissothatotherclasses,likeobjectfactories,canusetheActionProxyandother
//contextualinformationtooperate
ActionContextactionContext=ActionContext.getContext();
if(actionContext!=null){
actionContext.setActionInvocation(this);
}
//创建Action,可Struts2里是每次请求都新建一个Action
createAction(contextMap);
if(pushAction){
stack.push(action);
contextMap.put("action",action);
}
invocationContext=newActionContext(contextMap);
invocationContext.setName(proxy.getActionName());
//getanewListsowedon'tgetproblemswiththeiteratorifsomeonechangesthelist
ListinterceptorList=newArrayList(proxy.getConfig().getInterceptors());
interceptors=interceptorList.iterator();
}
protectedvoidcreateAction(MapcontextMap){
//loadaction
StringtimerKey="actionCreate:"+proxy.getActionName();
try{
UtilTimerStack.push(timerKey);
//这儿默认建立Action是StrutsObjectFactory,实际中我使用的时候都是使用Spring创建的Action,这个时候使用的是SpringObjectFactory
action=objectFactory.buildAction(proxy.getActionName(),proxy.getNamespace(),proxy.getConfig(),contextMap);
}
..
}finally{
UtilTimerStack.pop(timerKey);
}
if(actionEventListener!=null){
action=actionEventListener.prepare(action,stack);
}
}
StringprofileKey="invoke:";
try{
UtilTimerStack.push(profileKey);
if(executed){
thrownewIllegalStateException("Actionhasalreadyexecuted");
}
//先执行interceptors
if(interceptors.hasNext()){
finalInterceptorMappinginterceptor=(InterceptorMapping)interceptors.next();
UtilTimerStack.profile("interceptor:"+interceptor.getName(),
newUtilTimerStack.ProfilingBlock<String>(){
publicStringdoProfiling()throwsException{
resultCode=interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
returnnull;
}
});
}else{
//interceptor执行完了之后执行action
resultCode=invokeActionOnly();
}
//thisisneededbecausetheresultwillbeexecuted,thencontrolwillreturntotheInterceptor,whichwill
//returnaboveandflowthroughagain
if(!executed){
//在Result返回之前调用preResultListeners
if(preResultListeners!=null){
for(Iteratoriterator=preResultListeners.iterator();
iterator.hasNext();){
PreResultListenerlistener=(PreResultListener)iterator.next();
String_profileKey="preResultListener:";
try{
UtilTimerStack.push(_profileKey);
listener.beforeResult(this,resultCode);
}
finally{
UtilTimerStack.pop(_profileKey);
}
}
}
//nowexecutetheresult,ifwe'resupposedto
if(proxy.getExecuteResult()){
executeResult();
}
executed=true;
}
returnresultCode;
}
finally{
UtilTimerStack.pop(profileKey);
}
}StringmethodName=proxy.getMethod();
StringtimerKey="invokeAction:"+proxy.getActionName();
try{
UtilTimerStack.push(timerKey);
booleanmethodCalled=false;
ObjectmethodResult=null;
Methodmethod=null;
try{
//获得需要执行的方法
method=getAction().getClass().getMethod(methodName,newClass[0]);
}catch(NoSuchMethodExceptione){
//如果没有对应的方法,则使用do+Xxxx来再次获得方法
try{
StringaltMethodname="do"+methodName.substring(0,1).toUpperCase()+methodName.substring(1);
method=getAction().getClass().getMethod(altMethodName,newClass[0]);
}catch(NoSuchMethodExceptione1){
//well,givetheunknownhandlerashot
if(unknownHandler!=null){
try{
methodResult=unknownHandler.handleUnknownActionMethod(action,methodName);
methodCalled=true;
}catch(NoSuchMethodExceptione2){
//throwtheoriginalone
throwe;
}
}else{
throwe;
}
}
}
if(!methodCalled){
methodResult=method.invoke(action,newObject[0]);
}
//根据不同的Result类型返回不同值
//如输出流Result
if(methodResultinstanceofResult){
this.explicitResult=(Result)methodResult;
returnnull;
}else{
return(String)methodResult;
}
}catch(NoSuchMethodExceptione){
thrownewIllegalArgumentException("The"+methodName+"()isnotdefinedinaction"+getAction().getClass()+"");
}catch(InvocationTargetExceptione){
//Wetrytoreturnthesourceexception.
Throwablet=e.getTargetException();
if(actionEventListener!=null){
Stringresult=actionEventListener.handleException(t,getStack());
if(result!=null){
returnresult;
}
}
if(tinstanceofException){
throw(Exception)t;
}else{
throwe;
}
}finally{
UtilTimerStack.pop(timerKey);
}
}//根据ResultConfig创建Result
result=createResult();
StringtimerKey="executeResult:"+getResultCode();
try{
UtilTimerStack.push(timerKey);
if(result!=null){
//这儿正式执行:)
//可以参考Result的实现,如用了比较多的ServletDispatcherResult,ServletActionRedirectResult,ServletRedirectResult
result.execute(this);
}elseif(resultCode!=null&&!Action.NONE.equals(resultCode)){
thrownewConfigurationException("Noresultdefinedforaction"+getAction().getClass().getName()
+"andresult"+getResultCode(),proxy.getConfig());
}else{
if(LOG.isDebugEnabled()){
LOG.debug("Noresultreturnedforaction"+getAction().getClass().getName()+"at"+proxy.getConfig().getLocation());
}
}
}finally{
UtilTimerStack.pop(timerKey);
}
}
publicResultcreateResult()throwsException{
if(explicitResult!=null){
Resultret=explicitResult;
explicitResult=null;;
returnret;
}
ActionConfigconfig=proxy.getConfig();
Mapresults=config.getResults();
ResultConfigresultConfig=null;
synchronized(config){
try{
//根据result名称获得ResultConfig,resultCode就是result的name
resultConfig=(ResultConfig)results.get(resultCode);
}catch(NullPointerExceptione){
}
if(resultConfig==null){
//如果找不到对应name的ResultConfig,则使用name为*的Result
resultConfig=(ResultConfig)results.get("*");
}
}
if(resultConfig!=null){
try{
//参照StrutsObjectFactory的代码
Resultresult=objectFactory.buildResult(resultConfig,invocationContext.getContextMap());
returnresult;
}catch(Exceptione){
LOG.error("Therewasanexceptionwhileinstantiatingtheresultoftype"+resultConfig.getClassName(),e);
thrownewXWorkException(e,resultConfig);
}
}elseif(resultCode!=null&&!Action.NONE.equals(resultCode)&&unknownHandler!=null){
returnunknownHandler.handleUnknownResult(invocationContext,proxy.getActionName(),proxy.getConfig(),resultCode);
}
returnnull;
}
//StrutsObjectFactory
publicResultbuildResult(ResultConfigresultConfig,MapextraContext)throwsException{
StringresultClassName=resultConfig.getClassName();
if(resultClassName==null)
returnnull;
//创建Result,因为Result是有状态的,所以每次请求都新建一个
Objectresult=buildBean(resultClassName,extraContext);
//这句很重要,后面将会谈到,reflectionProvider参见OgnlReflectionProvider;
//resultConfig.getParams()就是result配置文件里所配置的参数<param></param>
//setProperties方法最终调用的是Ognl类的setValue方法
//这句其实就是把param名值设置到根对象result上
reflectionProvider.setProperties(resultConfig.getParams(),result,extraContext);
if(resultinstanceofResult)
return(Result)result;
thrownewConfigurationException(result.getClass().getName()+"doesnotimplementResult.");
}privateUseruser;
privateMapcontext;
@Before
publicvoidsetUp()throwsException{
}
@Test
publicvoidognlGetValue()throwsException{
reset();
Assert.assertEquals("myyate",Ognl.getValue("name",user));
Assert.assertEquals("cares",Ognl.getValue("dept.name",user));
Assert.assertEquals("myyate",Ognl.getValue("name",context,user));
Assert.assertEquals("contextmap",Ognl.getValue("#name",context,user));
Assert.assertEquals("parker",Ognl.getValue("#pen",context,user));
}
@Test
publicvoidognlSetValue()throwsException{
reset();
Ognl.setValue("name",user,"myyateC");
Assert.assertEquals("myyateC",Ognl.getValue("name",user));
Ognl.setValue("dept.name",user,"caresC");
Assert.assertEquals("caresC",Ognl.getValue("dept.name",user));
Assert.assertEquals("contextmap",Ognl.getValue("#name",context,user));
Ognl.setValue("#name",context,user,"contextmapC");
Assert.assertEquals("contextmapC",Ognl.getValue("#name",context,user));
Assert.assertEquals("parker",Ognl.getValue("#pen",context,user));
Ognl.setValue("#name",context,user,"parkerC");
Assert.assertEquals("parkerC",Ognl.getValue("#name",context,user));
}
publicstaticvoidmain(String[]args)throwsException{
JUnitCore.runClasses(TestOgnl.class);
}
privatevoidreset(){
user=newUser("myyate",newDept("cares"));
context=newOgnlContext();
context.put("pen","parker");
context.put("name","contextmap");
}
}
classUser{
publicUser(Stringname,Deptdept){
this.name=name;
this.dept=dept;
}
Stringname;
privateDeptdept;
publicDeptgetDept(){
returndept;
}
publicStringgetName(){
returnname;
}
publicvoidsetDept(Deptdept){
this.dept=dept;
}
publicvoidsetName(Stringname){
this.name=name;
}
}
classDept{
publicDept(Stringname){
this.name=name;
}
privateStringname;
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
}