最近因爲業務需求,幫同事把jsp頁面上的select控件進行了改動。可是在改完代碼以後,在某幾個擁有大量select組件的頁面下出現了報錯信息:_jspService超過了65535字節的限制。html
// 舊的代碼
<form:options items="${opts}" itemLabel="label" itemValue="value" htmlEscape="false"/>
// 新的代碼
<c:forEach items="${opts}" var="d">
<option value="d.value" label="d.label" title="d.label"></option>
</c:forEach>複製代碼
雖然這個問題經過其餘方式解決了。可是這個錯誤仍是一直困擾着我。正好今天沒什麼事情,就決定來看看這個的問題到底出在什麼地方。 由於問題頁面的其餘代碼都沒有改動過,因此咱們能夠很輕易的定位到咱們的問題代碼,也就是從options
到c:forEach
的改動。java
咱們先來了解一下jsp的編譯過程:首先,客戶端發送請求給web容器;而後,web容器將jsp文件編譯成servlet源碼,再將servlet源碼編譯成class文件;web容器執行class文件並將響應返回給客戶端。而咱們的遇到的錯誤信息是「unable to compile class for JSP」,而compile失敗的緣由呢就是_jspService
太大了。web
根據報錯信息,咱們得先找到_jspService這個方法。先從最簡單的空頁面開始調試,編譯運行後在瀏覽器裏訪問該頁面以生成java文件和class文件。下圖就是編譯後的class文件,咱們成功的找到了_jspService方法,同時咱們能夠看到,就是這個方法輸出了咱們的頁面。spring
接下來,我同時建立了兩個jsp頁面,裏面的內容就是最上面的代碼示例,一個頁面用options
標籤,另外一個頁面用了c:forEach
。下面貼上兩個jsp的編譯出來的class文件裏面的out.write()
部分代碼:瀏覽器
第一個jsp用的是options
標籤,從圖中能夠看到options
標籤沒有作任何的處理就編譯成了class文件。bash
第二個文件是用的c:forEach
,咱們發現class文件裏面已經沒有c:forEach
標籤了,取而代之的是一個if語句,而它的判斷條件是一個看起來與forEach有關的方法的返回值。來到這一步,答案其實已經呼之欲出了。咱們在這個文件中繼續查找,果真在下面出現了這個方法。jsp
這個方法內部有一個do{}while()
循環,全部的option都在這個循環中輸出。因爲這個方法太長了就不貼整個方法了,這個方法最終會返回false
,而後繼續執行_jspService
方法後續的out.write()
。函數
options
元素在jsp編譯成class的過程當中會被保留,到後面由spring MVC來處理,而每個c:forEach
標籤在編譯階段就已經被編譯成一個函數來輸出目標元素。若是form表單中須要大量的select
控件,最好能用options
來實現。固然,最好的方法仍是不要把太多的元素放到一個jsp中,能夠靈活的運用<jsp:include page="" flush="true" />
等方法來分解文件。spa