struts的执行流程

ActionServlet在系统启动时加载(load-on-startup=1)
struts加载流程:
一.加载内部资源文件
initInternal(),org.apache.struts.action下面的
ActionResources开头的两个文件

二.加载配置文件路径及处理向后兼容
initOther()获取config参数指定的要加载的配置文件的名称(多个之间用逗号分开),系统默认给定的
config值为/WEB-INF/struts-config.xml,如果获取的config不为空则用这个值代替系统值
并处理向后兼容的问题
三.加载ActionServlet的相关信息
initServlet()从web.xml中获取Action-servlet的配置信息(name,url-pattern等),它在解析的时候会调
用addServletMapping()将url-pattern的值传给servletMapping并将servletMapping放入servletContext
中(将/*.do放入了servletContext)

四.struts配置文件的初始化
1.ModuleConfig moduleConfig = initModuleConfig("", config);用于初始化ModuleConfig,它代理了一个
struts配置文件的内容(初始化完成后会以这个字名org.apache.struts.action.MODULE+prefix放入sevletContext
之中),默认配置文件是没有前缀的,多模块开发的时候才有,就是web.xml中的config/prefix后面这个prefix)
initModuleConfig(String prefix, String paths)方法中的config会按逗号分割成多个配置文件路径,并解析到一个ModuleConfig中
2.获取ModuleConfig对象
ModuleConfigFactory factoryObject = ModuleConfigFactory.createFactory();
ModuleConfig config = factoryObject.createModuleConfig(prefix);
这两句话是创造一个ModuleConfig的实例,工厂比较简单,直接new了一个ModuleConfigImpl的对象并返回
ModuleConfigImpl里面可值得一看了,它里面有整个struts配置文件所具有的各种配置信息(如datasource,formbean等),它定义了
大量的hashmap来存放这些配置信息对应的对象(如actionConfigs用于存放actionmapping对象信息),可以把它看成一个容器
3.解析struts配置信息,并将产生的相关配置对象放入moduleconfig对象之中
Digester digester = initConfigDigester();这句是用来解析struts配置文件所用
initConfigDigester()中configDigester.addRuleSet(new ConfigRuleSet());为解析配置规则
进去ConfigRuleSet类中,下面是类中的一段注释
*These rules assume that an instance of
* <code>org.apache.struts.config.ModuleConfig</code> is pushed
* onto the evaluation stack before parsing begins.
我对Digester不是太懂,我这里是这样猜想的(应该没有错)digester在解析时,可以调用一个压入
stack的对象的方法(如解析了datasoure,那么要将这个对象添加到相应的ModuleConfigImpl对象之中),
如下,在解析datasource的时候就有这样一句(其它所有的都有类似的)
digester.addSetNext
            ("struts-config/data-sources/data-source",
             "addDataSourceConfig",//ModuleConfigImpl有一个addDataSourceConfig方法,用于添加DataSourceConfig对象
             "org.apache.struts.config.DataSourceConfig");
添加完规则后就回到initModuleConfig()方法中去,解析开始:
将config对应的路径进行处理,如果有多个文件就一个一个解析(看来它把这多个文件是当成一个模块来处理的),
解析完成后将moduleConfig对象放入sevletContext
五.加载国际化文件
initModuleMessageResources(moduleConfig)
首先取出所有的MessageResourcesConfig对象MessageResourcesConfig mrcs[] = config.findMessageResourcesConfigs();
先建一个工厂对象(org.apache.struts.util.PropertyMessageResourcesFactory),然后取出MessageResourcesConfig对象中
的parameter值,它不正是那个路径么,从而new一个PropertyMessageResources的对象,实际上起作用的只有路径
PropertyMessageResources有个getMessage方法,当调用它时,它会调用loadLocale方法,它首先判断这个key找不找得到,
找不到的话它会加载指定路径的资源文件(它首先对路径进行处理将.换成/,也就是说com.abc.zengge将会加载com/abc/zengge_*.properties),
并将相应的信息放入messages这个hashmap,说明资源文件是在第一次访问时才真正的加载起来

六.初始化数据源
initModuleDataSources(),从moduleconfig中取出所有的DataSourceConfig对象,根据里面的类型信息,用户,密码等产生出
一个datasource对象(这些信息存在一个hashmap中,用BeanUtils直接将值给弄进datasource对象)

七.初始化plugin
initModulePlugIns(),(以ValidatorResources为例)根据className定义的类实例化一个Plugin对象,
并将hashmap中的值全弄进plugin,接着调用init方法,init方法默认取出property名字为pathnames的值,
并将值按逗号进行分割,并加载分割后的路径的文件,一个文件对应一个ValidatorResources

一个ModuleConfig加载完成,调用其freeze(),防止己加载的配置信息被修改(比如ActoinConfig对应path为path1,
加载后你就不能想改为path2)

加载完默认或web.xml中指定的配置文件后就得加载分模块的配置文件了,以config/*命名的参数的值,过程同上(四到七步),
先moduleconfig,再datasource,messageresource,plugin

所有的配置文件加载完成后,将用到的前缀放进servletcontext中


请求的执行流程:
一.获取RequestProcessor对象,struts将所有的请求委托给它处理(像用spring管理action的DelegatingRequestProcessor就是它的子类)
,接着调用它的init方法(将action清空,action是放在它的hashmap中的,action是实例化一次)

二.doGet或doPost调用RequestProcessor类的process(request,response)方法
2.1 processLocale(request, response)方法将locale信息存入session
2.2 processContent(request, response)有contentType就设置它response.setContentType()
     processNoCache(request, response)有nocache就在头里面设置它response.setHeader("Pragma", "No-cache")等
2.3 processCachedMessages(request, response)去除session中的ActionMessages
session.removeAttribute(Globals.ERROR_KEY);
session.removeAttribute(Globals.MESSAGE_KEY);
2.4处理ActionMapping啦
    processMapping(request, response, path)中的
ActionMapping mapping = (ActionMapping)
            moduleConfig.findActionConfig(path);根据请求path得到mapping对象
ModuleConfigImpl(moduleConfig)对象里面有大量的hashmap,看看下面这些名字
actionConfigs,dataSources,exceptions,formBeans,forwards,messageResources,plugIns
及一个list:actionConfigList(ActionConfig是ActionMapping的父类)
对于actionConfig的map与list意义好像是一样的啊
如果得到的mapping为空,那么去取unknown为true的action(默认action),如果没定义,就准备
接错误信息吧

2.5到了ActionForm了哦
    ActionForm form = processActionForm(request, response, mapping);
    processPopulate(request, response, form, mapping);

a.processActionForm方法最精华的一句
ActionForm instance = RequestUtils.createActionForm
            (request, mapping, moduleConfig, servlet);
//得到action的name属性(不就是form的名字吗),那个有好多hashmap的对象得去找对应的Form了哦
String name = mapping.getName();
    FormBeanConfig config = moduleConfig.findFormBeanConfig(name);
FormBeanConfig有一个hashmap叫作formProperties,估计它用来记录actionform的属性
这是原话(A JavaBean representing the configuration information of a actionform)
上面的理解有误啦formProperties:The set of FormProperty elements defining dynamic form properties for
     * this form bean, keyed by property name.
仔细一看FormBeanConfig里面常用的属性都有对应的方法了,看来这个hashmap是对应于这种东东的LazyValidatorForm

这句话就更得注意了:ActionForm instance = lookupActionForm(request, attribute, mapping.getScope());
String attribute = mapping.getAttribute()首先取出这个form对应的存在request或session中的名字,这里要注意一下的
就是在mapping.getAttribute()中当没有定义attribute时默认返回的是name的值
接着从scope定义的范围中取出actionForm,如果没取到就调用createActionForm方法,它会用反射机制来为产生一个form对象,
接着就将产生的form放到request或者是session中

b.processPopulate年名字就知道要给actionform填值啦
form.reset(mapping, request);执行reset方法
接着就要往form填值了
RequestUtils.populate(form, mapping.getPrefix(), mapping.getSuffix(),
                              request);
这个方法首先判断是否为文件上传请求,如果不是则将请求的参数与值放到一个hashmap之中去,
这个相信大家都会明白的BeanUtils.populate(bean, properties),所以这个时候form的set方法会被调用

接下来就执行form的validate方法,成功就往下进行
processValidate(request, response, form, mapping)

2.6 属性forward
如果从mapping中能找到forward(这对应action中的forward属性,而不是forward的元素),就直接跳转了
processForward(request, response, mapping)

2.7 include页面
processInclude(request, response, mapping)取得到include的话就包含页面,并停止向下执行

2.8 action
Action action = processActionCreate(request, response, mapping);建一个相应的action对象,首先从
hashmap中找,找不到才新建(在spring管理时,直接用WebApplicationContext去getBean)

ActionForward forward =
            processActionPerform(request, response,action, form, mapping);这句话会执行
大家平时override父Action的execute方法

processForwardConfig(request, response, forward);处理跳转,forward中是包含有路径信息的哦,
取出来就可以转发了或跳转了


DispatchAction的可取之处:
String parameter = getParameter(mapping, form, request, response);取出mapping中的parameter的值
String name = getMethodName(mapping, form, request, response, parameter);的实质是request.getParameter(parameter)根据parameter的值取出方法名

有了方法名就可以用反射取出Method对象并执行了,在这里struts做的更好了,它定义了一个methods的hashmap,
key为methodname,value为Method对象,它首先会根据方法名去找有没有这个Method的对象,如果有就直接用,否则就
class.getMethod(name,type)获取Method对象并将它们放过hashmap,也就是说所有的Method对象只建一次就OK了

你可能感兴趣的:(apache,spring,bean,struts,配置管理)