Jasper 2 JSP 引擎操作指南

目錄

簡介

Tomcat 10.1 使用 Jasper 2 JSP 引擎來實作 JavaServer Pages 2.3 規範。

Jasper 2 經過重新設計,大幅提升效能,優於原本的 Jasper。除了改善整體程式碼外,還進行了以下變更

  • JSP 自訂標籤池 - 現在可以將為 JSP 自訂標籤實例化的 Java 物件集中並重複使用。這大幅提升使用自訂標籤的 JSP 頁面效能。
  • 背景 JSP 編譯 - 如果您變更已編譯的 JSP 頁面,Jasper 2 可以於背景中重新編譯該頁面。先前編譯的 JSP 頁面仍可提供服務。一旦新頁面編譯成功,就會取代舊頁面。這有助於提升 JSP 頁面在生產環境伺服器上的可用性。
  • 在包含的頁面變更時重新編譯 JSP - Jasper 2 現在可以偵測到從 JSP 編譯時包含的頁面發生變更,然後重新編譯父 JSP。
  • JDT 用於編譯 JSP 頁面 - Eclipse JDT Java 編譯器現在用於執行 JSP Java 原始碼編譯。此編譯器從容器類別載入器載入原始碼相依性。仍可使用 Ant 和 javac。

Jasper 使用 servlet 類別 org.apache.jasper.servlet.JspServlet 實作。

設定

預設情況下,Jasper 設定為在執行 Web 應用程式開發時使用。請參閱區段 生產設定,以取得有關在生產 Tomcat 伺服器上設定 Jasper 使用的資訊。

實作 Jasper 的 servlet 使用全域 $CATALINA_BASE/conf/web.xml 中的初始化參數進行設定。

  • checkInterval - 如果開發為 false,且 checkInterval 大於 0,則會啟用背景編譯。checkInterval 是檢查 JSP 頁面(及其相依檔案)是否需要重新編譯的檢查間隔時間(以秒為單位)。預設為 0 秒。
  • classdebuginfo - 是否應該使用除錯資訊編譯類別檔案?truefalse,預設為 true
  • classpath - 定義用於編譯產生之 servlet 的類別路徑。此參數僅在 ServletContext 屬性 org.apache.jasper.Constants.SERVLET_CLASSPATH 未設定時才會生效。當在 Tomcat 中使用 Jasper 時,此屬性始終會設定。預設情況下,類別路徑會根據目前的 Web 應用程式動態建立。
  • compiler - Ant 應使用哪個編譯器來編譯 JSP 頁面。此處的有效值與 Ant 的 javac 工作的 compiler 屬性相同。如果未設定值,則會使用預設的 Eclipse JDT Java 編譯器,而不是使用 Ant。沒有預設值。如果設定此屬性,則應使用 setenv.[sh|bat]ant.jarant-launcher.jartools.jar 新增至 CLASSPATH 環境變數。
  • compilerSourceVM - 原始碼檔案與哪個 JDK 版本相容?(預設值:11
  • compilerTargetVM - 已產生檔案相容的 JDK 版本為何?(預設值:11
  • development - Jasper 是否用於開發模式?若為 true,則可透過 modificationTestInterval 參數指定檢查 JSP 是否有修改的頻率。truefalse,預設為 true
  • displaySourceFragment - 是否應在例外狀況訊息中包含原始碼片段?truefalse,預設為 true
  • dumpSmap - 是否應將 JSR45 除錯的 SMAP 資訊傾印至檔案?truefalse,預設為 false。若 suppressSmap 為 true,則為 false
  • enablePooling - 決定是否啟用標籤處理常式。這是編譯選項。它不會變更已編譯 JSP 的行為。truefalse,預設為 true
  • engineOptionsClass - 允許指定用於設定 Jasper 的 Options 類別。若不存在,則會使用預設的 EmbeddedServletOptions。若在 SecurityManager 下執行,則會略過此選項。
  • errorOnUseBeanInvalidClassAttribute - 當 useBean 動作中 class 屬性的值不是有效的 bean 類別時,Jasper 是否應發出錯誤?truefalse,預設為 true
  • fork - 讓 Ant 分岔 JSP 頁面編譯,以便在 Tomcat 的獨立 JVM 中執行?truefalse,預設為 true
  • genStringAsCharArray - 是否應將文字字串產生為字元陣列,以在某些情況下提升效能?預設為 false
  • javaEncoding - 用於產生 Java 原始碼檔案的 Java 檔案編碼。預設為 UTF8
  • keepgenerated - 我們是否應保留每個頁面的已產生 Java 原始碼,而不是刪除它?truefalse,預設為 true
  • mappedfile - 我們是否應產生每個輸入列只有一個列印陳述式的靜態內容,以簡化除錯?truefalse,預設為 true
  • maxLoadedJsps - 將為 Web 應用程式載入的 JSP 的最大數量。若載入的 JSP 數量超過此數字,則會卸載最近最少使用的 JSP,以使任何時間載入的 JSP 數量不超過此限制。零或負值表示沒有限制。預設為 -1
  • jspIdleTimeout - JSP 在卸載前可以閒置的秒數。零或負值表示永不卸載。預設為 -1
  • modificationTestInterval - 導致 JSP(及其相關檔案)在最後一次檢查 JSP 是否有修改後的指定時間間隔(以秒為單位)內,不會被檢查是否有修改。值 0 會導致在每次存取時檢查 JSP。僅在開發模式中使用。預設為 4 秒。
  • recompileOnFail - 如果 JSP 編譯失敗,是否應忽略 modificationTestInterval,而讓下次存取觸發重新編譯嘗試?僅在開發模式中使用,且預設為停用,因為編譯可能很耗費資源,並可能導致過度使用資源。
  • scratchdir - 編譯 JSP 頁面時,我們應使用哪個暫存目錄?預設為目前 Web 應用程式的作業目錄。如果在 SecurityManager 下執行,則會忽略此選項。
  • suppressSmap - 是否應抑制產生用於 JSR45 除錯的 SMAP 資訊?truefalse,預設為 false
  • trimSpaces - 是否應從輸出中移除完全由空白組成的範本文字(true)、用一個空白取代(single)或不變更(false)?或者,extended 選項會從範本文字中移除前導和尾隨空白,並將範本文字中的空白和換行符號序列壓縮成單一新行。請注意,如果 JSP 頁面或標籤檔案指定 trimDirectiveWhitespaces 值為 true,則該值會優先於該頁面/標籤的此組態設定。預設為 false
  • xpoweredBy - 決定是否由產生的 servlet 加入 X-Powered-By 回應標頭。truefalse,預設為 false
  • strictQuoteEscaping - 當使用指令碼片段表達式作為屬性值時,是否應嚴格套用 JSP.1.6 中的引號字元跳脫規則?truefalse,預設為 true
  • quoteAttributeEL - 當在 JSP 頁面的屬性值中使用 EL 時,是否應將 JSP.1.6 中描述的屬性引號規則套用至表達式?truefalse,預設為 true
  • variableForExpressionFactory - 要用於表達式語言表達式工廠的變數名稱。如果未指定,則會使用預設值 _el_expressionfactory
  • variableForInstanceManager - 要用於實例管理員工廠的變數名稱。如果未指定,則會使用預設值 _jsp_instancemanager
  • poolTagsWithExtends - 預設情況下,透過頁面指令的 extends 屬性使用其自己的基本類別的 JSP 會停用標籤池,因為 Jasper 無法保證已執行必要的初始化。這可能會對效能產生負面影響。如果替代基本類別從 Servlet.init() 呼叫 _jspInit(),則將此屬性設定為 true 會使用替代基本類別啟用池。如果替代基本類別未呼叫 _jspInit() 而此屬性為 true,則嘗試使用標籤時會發生 NPE。truefalse,預設為 false
  • strictGetProperty - 如果為 true,則會強制執行在 JSP 2.0 和後續規格的 JSP.5.3 章節中指定的,在 jsp:getProperty 動作中引用的物件必須先前「引入」到 JSP 處理器的需求。truefalse,預設為 true
  • strictWhitespace - 如果為 false,則會放寬屬性名稱前空白的要求,這樣一來,沒有空白就不會造成錯誤。truefalse,預設為 true
  • jspServletBase - 從 JSP 產生的 Servlet 的基礎類別。如果未指定,則會使用 org.apache.jasper.runtime.HttpJspBase 的預設值。
  • serviceMethodName - 基礎類別所呼叫的服務方法名稱。如果未指定,則會使用 _jspService 的預設值。
  • servletClasspathAttribute - 提供 JSP 類別路徑的 ServletContext 屬性名稱。如果未指定,則會使用 org.apache.catalina.jsp_classpath 的預設值。
  • jspPrecompilationQueryParameter - 導致 JSP 引擎僅預先產生 servlet 但不呼叫它的查詢參數名稱。如果未指定,則會使用 JSP 規格 (JSP.11.4.2) 所定義的 jsp_precompile 預設值。
  • generatedJspPackageName - 編譯 JSP 的預設套件名稱。如果未指定,則會使用 org.apache.jsp 的預設值。
  • generatedTagFilePackageName - 從標籤檔案產生的標籤處理常式的預設套件名稱。如果未指定,則會使用 org.apache.jsp.tag 的預設值。
  • tempVariableNamePrefix - 用於產生的暫時變數名稱的前置詞。如果未指定,則會使用 _jspx_temp 的預設值。
  • useInstanceManagerForTags - 如果為 true,則會使用執行個體管理員來取得標籤處理常式執行個體。truefalse,預設為 false
  • limitBodyContentBuffer - 如果為 true,則任何擴充至 bodyContentTagBufferSize 初始化參數值以外的標籤緩衝區都會被銷毀,並建立新的緩衝區。truefalse,預設為 false
  • bodyContentTagBufferSize - 建立標籤緩衝區時要使用的 (字元) 大小。如果未指定,則會使用 org.apache.jasper.Constants.DEFAULT_TAG_BUFFER_SIZE (512) 的預設值。

Eclipse JDT 中的 Java 編譯器包含在預設編譯器中。它是一個進階 Java 編譯器,它會從 Tomcat 類別載入器載入所有相依性,這將在大型安裝中編譯數十個 JAR 時提供極大的幫助。在快速伺服器上,這將允許即使是大型 JSP 頁面也能進行次秒重新編譯週期。

Apache Ant,它用於先前 Tomcat 版本中,可以使用它來取代新的編譯器,方法是按照上述說明配置編譯器屬性。

如果您需要變更應用程式的 JSP Servlet 設定,您可以透過在 /WEB-INF/web.xml 中重新定義 JSP Servlet 來覆寫預設組態。然而,如果您嘗試在另一個容器中部署應用程式,這可能會造成問題,因為 JSP Servlet 類別可能無法辨識。您可以透過使用 Tomcat 特定的 /WEB-INF/tomcat-web.xml 部署描述符來解決這個問題。格式與 /WEB-INF/web.xml 相同。它將覆寫任何預設設定,但不會覆寫 /WEB-INF/web.xml 中的設定。由於它是 Tomcat 特定的,因此只有在應用程式部署在 Tomcat 上時才會處理它。

已知問題

錯誤 39089 中所述,已知的 JVM 問題,錯誤 6294277,可能會在編譯非常大的 JSP 時造成 java.lang.InternalError: name is too long to represent 例外。如果觀察到這一點,則可以使用下列其中一項來解決

  • 縮小 JSP 的大小
  • 透過將 suppressSmap 設定為 true 來停用 SMAP 產生和 JSR-045 支援。

生產環境設定

可以執行的主要 JSP 最佳化是 JSP 的預編譯。然而,這可能無法執行(例如,在使用 jsp-property-group 功能時)或不切實際,在這種情況下,Jasper servlet 的組態變得至關重要。

在生產 Tomcat 伺服器中使用 Jasper 2 時,您應該考慮從預設組態中進行下列變更。

  • 開發 - 若要停用對 JSP 頁面編譯的存取檢查,請將其設定為 false
  • genStringAsCharArray - 若要產生效率稍高的字元陣列,請將此設定為 true
  • modificationTestInterval - 如果開發必須設定為 true(例如動態產生 JSP),將此設定為高值將大幅改善效能。
  • trimSpaces - 若要從回應中移除不必要的位元組,請考慮將此設定為 singleextended

Web 應用程式編譯

使用 Ant 是使用 JSPC 編譯 Web 應用程式的首選方式。請注意,在預編譯 JSP 時,只有在 suppressSmap 為 false 且 compile 為 true 的情況下,SMAP 資訊才會包含在最終類別中。使用以下指令碼(「deployer」下載中包含類似的指令碼)預編譯 Web 應用程式

<project name="Webapp Precompilation" default="all" basedir=".">

   <import file="${tomcat.home}/bin/catalina-tasks.xml"/>

   <target name="jspc">

    <jasper
             validateXml="false"
             uriroot="${webapp.path}"
             webXmlInclude="${webapp.path}/WEB-INF/generated_web.xml"
             outputDir="${webapp.path}/WEB-INF/src" />

  </target>

  <target name="compile">

    <mkdir dir="${webapp.path}/WEB-INF/classes"/>
    <mkdir dir="${webapp.path}/WEB-INF/lib"/>

    <javac destdir="${webapp.path}/WEB-INF/classes"
           debug="on" failonerror="false"
           srcdir="${webapp.path}/WEB-INF/src"
           excludes="**/*.smap">
      <classpath>
        <pathelement location="${webapp.path}/WEB-INF/classes"/>
        <fileset dir="${webapp.path}/WEB-INF/lib">
          <include name="*.jar"/>
        </fileset>
        <pathelement location="${tomcat.home}/lib"/>
        <fileset dir="${tomcat.home}/lib">
          <include name="*.jar"/>
        </fileset>
        <fileset dir="${tomcat.home}/bin">
          <include name="*.jar"/>
        </fileset>
      </classpath>
      <include name="**" />
      <exclude name="tags/**" />
    </javac>

  </target>

  <target name="all" depends="jspc,compile">
  </target>

  <target name="cleanup">
    <delete>
        <fileset dir="${webapp.path}/WEB-INF/src"/>
        <fileset dir="${webapp.path}/WEB-INF/classes/org/apache/jsp"/>
    </delete>
  </target>

</project>

可以使用以下命令列執行指令碼(將代碼替換為 Tomcat 基礎路徑和應預編譯的 Web 應用程式路徑)

$ANT_HOME/bin/ant -Dtomcat.home=<$TOMCAT_HOME> -Dwebapp.path=<$WEBAPP_PATH>

然後,必須將預編譯期間產生的 servlet 宣告和對應新增到 Web 應用程式部署描述符。將 ${webapp.path}/WEB-INF/generated_web.xml 插入 ${webapp.path}/WEB-INF/web.xml 檔案中的正確位置。重新啟動 Web 應用程式(使用管理員),並測試它以驗證它能順利執行預編譯的 servlet。也可以在 Web 應用程式部署描述符中放置適當的代碼,以使用 Ant 過濾功能自動插入產生的 servlet 宣告和對應。這實際上是所有與 Tomcat 一起發布的 Web 應用程式在建置過程中自動編譯的方式。

在 jasper 任務中,您可以使用選項 addWebXmlMappings 自動將 ${webapp.path}/WEB-INF/generated_web.xml 與目前的 Web 應用程式部署描述符 ${webapp.path}/WEB-INF/web.xml 合併。

當您想為 JSP 使用特定版本的 Java 時,請新增 javac 編譯器任務屬性 sourcetarget,並指定適當的值。例如,16 可為 Java 16 編譯 JSP。

對於製作,您可能希望使用 debug="off" 停用偵錯資訊。

當您不希望在第一個 JSP 語法錯誤時停止 JSP 產生時,請使用 failOnError="false",並使用 showSuccess="true" 列印出所有成功的「JSP 轉 Java」產生。當您清除 ${webapp.path}/WEB-INF/src 中產生的 Java 原始檔和編譯 ${webapp.path}/WEB-INF/classes/org/apache/jsp 中的 JSP servlet 類別時,這有時非常有幫助。

提示

  • 當您切換到另一個 Tomcat 版本時,請使用新的 Tomcat 版本重新產生和重新編譯您的 JSP。
  • 使用 Servlet 內容參數停用 PageContext 池 org.apache.jasper.runtime.JspFactoryImpl.POOL_SIZE=-1,並使用 JSP Servlet 初始化參數 limitBodyContentBuffer=true 限制緩衝。請注意,從預設值變更可能會影響效能,但會因應用程式而異。

最佳化

Jasper 中提供多個擴充功能點,使用戶能夠針對其環境最佳化行為。

這些擴充功能點中,第一個是標籤外掛程式機制。這允許提供標籤處理常式的替代實作,供 Web 應用程式使用。標籤外掛程式透過位於 WEB-INF 下的 tagPlugins.xml 檔案進行註冊。Jasper 中包含一個 JSTL 的範例外掛程式。

第二個擴充功能點是表達式語言直譯器。可以透過 ServletContext 設定替代直譯器。請參閱 ELInterpreterFactory javadoc,以取得如何設定替代 EL 直譯器的詳細資料。一個主要針對標籤設定的替代直譯器提供在 org.apache.jasper.optimizations.ELInterpreterTagSetters。請參閱 javadoc,以取得最佳化的詳細資料,以及它們對規格相容性的影響。

也提供一個擴充功能點,用於將字串值轉換為列舉。它提供在 org.apache.jasper.optimizations.StringInterpreterEnum。請參閱 javadoc,以取得最佳化的詳細資料,以及它們對規格相容性的影響。