看了很多的資料書(shū)籍,都提了一下ActionForm的生命周期。例如,在“Programming Jakarta Struts"中是這樣描述的:“控制器收到的請
求”->“創(chuàng )建或再循環(huán)ActionForm”->“調用reset()“->“正確保存ActionForm”->“由請求組合ActionForm”->“驗證ActionForm”。如果
驗證不通過(guò)返回到輸入,否則調用Action的execute()方法。
我們來(lái)看一看RequestProcessor()的process()方法的部分代碼。經(jīng)過(guò)一些基本的處理(如Locale,Role等)之后,會(huì )調用processActionForm
方法,此方法返回一個(gè)ActionForm。然后用processPopulate方法將請求參數傳給這個(gè)ActionForm,之后進(jìn)行驗證。 // Process any ActionForm bean related to this request ActionForm form = processActionForm(request, response, mapping); processPopulate(request, response, form, mapping); if (!processValidate(request, response, form, mapping)) { return; } processActionForm()方法又調用RequestUtils.createActionForm()這個(gè)靜態(tài)方法來(lái)創(chuàng )建ActionForm,并把創(chuàng )建的ActionForm保
存在合適的作用域,以便下次使用。 RequestUtils.createActionForm()方法并不是一上來(lái)就創(chuàng )建ActionForm,而是先查看一下在合適的作用域內有沒(méi)有存在的ActionForm if ("request".equals(mapping.getScope())) { instance = (ActionForm) request.getAttribute(attribute); } else { session = request.getSession(); instance = (ActionForm) session.getAttribute(attribute); } 如果沒(méi)找到,才會(huì )根據struts-config.xml中的actionmapping找到name屬性(ActionForm的邏輯名),根據邏輯名再找到ActionForm
的類(lèi)名,然后會(huì )用類(lèi)似Class.forName("ActionForm‘‘s full class name").newInstance()來(lái)動(dòng)態(tài)創(chuàng )建這個(gè)ActionForm類(lèi)的實(shí)例。當然,它還要
考慮DynaActionForm的情況,但原理是一樣的。 這么看來(lái),ActionForm的生命周期不算復雜,也沒(méi)有“探”的必要。 在工作中,發(fā)現實(shí)際情況并不這么簡(jiǎn)單。
由于工作需要,我們要做一個(gè)通用的Action,它可以處理很多的ActionForm。這有點(diǎn)意思,別人做的是一個(gè)ActionForm被好幾個(gè)Action使用,
而我們卻恰恰相反。因此我用自定義的RequestProcessor代替的默認的,并重寫(xiě)了它的processActionForm()方法。在處理一個(gè)JSP頁(yè)面時(shí),
發(fā)現創(chuàng )建ActionForm的時(shí)候根本沒(méi)有調用我的processActionForm()方法,開(kāi)始我還以為是struts-config.xml文件沒(méi)有配置好,又在父類(lèi)的p
rocess()(processActionForm方法的調用者)里設了斷點(diǎn),結果也沒(méi)有停下。弄了半天也沒(méi)找出是那出了問(wèn)題,連ActionServlet的init()
里設斷點(diǎn)也沒(méi)停下來(lái)。但RequestUtil.createActionForm()還是被調用了。我并沒(méi)有請求一個(gè)Action(xxx.do),但怎么會(huì )創(chuàng )建一個(gè)ActionFor
m呢?而且RequestProcess的process()方法也沒(méi)被調用。這就比較奇怪了,難道是struts出bug了,抑或是JBuilder出bug了? 后來(lái)仔細檢查,發(fā)現struts自定義標簽是“罪魁禍首”。 到底是怎么回事呢?原來(lái)我在那個(gè)JSP中使用的<html:form action="xxxx.do">的標簽,它會(huì )創(chuàng )建一個(gè)ActionForm。 具體的過(guò)程為:org.apache.struts.taglib.html.FormTag的 doStartTag()方法一開(kāi)始就調用this.lookup()方法,來(lái)得到在<html:form action="xx.do">的那個(gè)actionmapping的信息,進(jìn)而得
到于這個(gè)action關(guān)聯(lián)的ActionForm的信息。返回doStartTag()方法后,會(huì )在后面的this.initFormBean()方法中調用RequestUtils.createA
ctionForm()方法創(chuàng )建或回收一個(gè)ActionForm。 到這時(shí),我們知道了為什么會(huì )出現問(wèn)題。但卻想不明白為什么<html:form>的標簽處理類(lèi)這么早就創(chuàng )建一個(gè)ActionForm。是為了檢查我
們在<html:text property="xxx"/>中的屬性是否存在?還有一個(gè)有趣的地方:這個(gè)ActionForm(我是用的request作用域)在這個(gè)JSP提交后并
不能被重用,想想也是:請求這個(gè)JSP是一個(gè)完整的請求,再請求xxx.do又是一個(gè)不同的請求,當然不能再用。也就是說(shuō),這個(gè)ActionForm除了
能檢驗嵌套在<html:form>內的標簽的property是否正確外沒(méi)有別的作用。如果你想提高性能(不知道能提高多少)的話(huà),可以用靜態(tài)的html標
簽<form>,這樣它就不會(huì )創(chuàng )建一個(gè)沒(méi)有什么作用的ActionForm了。