鍍金池/ 教程/ Linux/ JSPs
連接器
JSPs
重寫機(jī)制
CGI
Tomcat Manager
Windows 認(rèn)證
代理支持
虛擬主機(jī)
安全性注意事項(xiàng)
如何在 Maven 中使用 Tomcat 庫
安裝
MBean 描述符
JNDI 資源
類加載機(jī)制
Tomcat Web 應(yīng)用部署
基于 APR 的原生庫
負(fù)載均衡器
安全管理
附加組件
監(jiān)控與管理
Windows 服務(wù)
集群化與會(huì)話復(fù)制
高級(jí) IO 機(jī)制
SSI(服務(wù)器端嵌入)
WebSocket 支持
JDBC 數(shù)據(jù)源
日志機(jī)制
默認(rèn) Servlet
SSL/TLS 配置
Tomcat 的 JDBC 連接池
第一個(gè)應(yīng)用
簡介
Realm 配置

JSPs

簡介

Tomcat 8.0 使用 Jasper 2 JSP 引擎去實(shí)現(xiàn) JavaServer Pages 2.3 規(guī)范。

Jasper 2 經(jīng)過了重新設(shè)計(jì),極大改善了上一版 Jasper 的性能。除了一般性的代碼改進(jìn)之外,還做出了以下改變:

  • JSP 自定義標(biāo)簽池化 針對 JSP 自定義標(biāo)簽(JSP Custom Tags)實(shí)例化的 Java 對象現(xiàn)已可以被池化和重用,從而極大提高了使用自定義標(biāo)簽的 JSP 頁面的性能。
  • JSP 后臺(tái)編譯 如果你更改了一個(gè)已經(jīng)編譯的 JSP 頁面,Jasper 2 會(huì)在后臺(tái)重新編譯該頁面。之前編譯的 JSP 頁面將依然能夠服務(wù)請求。一旦新頁面編譯成功,它就會(huì)自動(dòng)代替舊頁面。這能提高生產(chǎn)服務(wù)器上的 JSP 頁面的可用性。
  • 能夠重新編譯發(fā)生改動(dòng)的 JSP 頁面 Jasper 2 現(xiàn)在能夠偵測頁面何時(shí)出現(xiàn)改動(dòng),然后重新編譯父 JSP。
  • 用于編譯 JSP 頁面的 JDT 編譯器 Eclipse JDT Java 編譯器現(xiàn)在能用來編譯 JSP java 源代碼。該編譯器從容器類加載器加載源代碼支持。Ant 與 javac 依舊能夠使用。

Jasper 可以使用 servlet 類 org.apache.jasper.servlet.JspServlet。

配置

Jasper 默認(rèn)就是用于開發(fā) Web 應(yīng)用的。關(guān)于如何在 Tomcat 生產(chǎn)服務(wù)器中配置并使用 Jasper,可參考生產(chǎn)環(huán)境配置一節(jié)內(nèi)容。

在全局性的 $CATALINA_BASE/conf/web.xml 中使用如下初始參數(shù),來配置實(shí)現(xiàn) Jasper 的 servlet。

  • checkInterval 如果 development 為 false,并且checkInterval 大于 0,則開啟后臺(tái)編譯。checkInterval 參數(shù)的含義就是在檢查某個(gè) JSP 頁面(以及從屬文件)是否需要重新編譯時(shí),幾次檢查的間隔時(shí)間(以秒計(jì))。默認(rèn)為 0 秒。

  • classdebuginfo 是否應(yīng)在編譯類文件時(shí)帶上調(diào)試信息?布爾值,默認(rèn)為 true。

  • classpath 對生成的 servlet 進(jìn)行編譯時(shí)將要使用的類路徑。如果 ServletContext 屬性 org.apache.jasper.Constants.SERVLET_CLASSPATH 沒有設(shè)置。當(dāng)在 Tomcat 中使用 Jasper 時(shí),該屬性經(jīng)常設(shè)置。默認(rèn)情況下,根據(jù)當(dāng)前 Web 應(yīng)用,動(dòng)態(tài)創(chuàng)建類路徑。

  • compiler 應(yīng)用何種編譯器 Ant 編譯 JSP 頁面。該參數(shù)的有效值與 Ant 的 javac 任務(wù)的編譯器屬性值完全相同。如果沒有設(shè)置該值,則采用默認(rèn)的 Eclipse JDT Java 編譯器,而不是 Ant。該參數(shù)沒有默認(rèn)值,如果該屬性被設(shè)置,則就應(yīng)該使用 setenv.[sh|bat]ant.jar、ant-launcher.jartools.jar 添加到 CLASSPATH 環(huán)境變量中。

  • compilerSourceVM 與源文件所兼容的 JDK 版本?(默認(rèn)值:1.7

  • compilerTargetVM 與生成文件所兼容的 JDK 版本?(默認(rèn)值:1.7

  • development Jasper 是否被用于開發(fā)模式?如果為 true,可能通過 modificationTestInterval 參數(shù)來指定檢查 JSP 更改情況的頻率。布爾值,默認(rèn)為 true。

  • displaySourceFragment 異常信息是否應(yīng)包含源代碼片段?布爾值,默認(rèn)為 true

  • dumpSmap JSR45 調(diào)試的 SMAP 信息是否應(yīng)轉(zhuǎn)儲(chǔ)到一個(gè)文件?布爾值,默認(rèn)為 false。如果 suppressSmaptrue,則該參數(shù)值為 false。

  • enablePooling 是否啟用標(biāo)簽處理池(tag handler pooling)?這是一個(gè)編譯選項(xiàng)。它不會(huì)影響已編譯的 JSP 行為。布爾值,默認(rèn)為 true。

  • engineOptionsClass 允許指定用來配置 Jasper 的 Options 類。如果不存在,則使用默認(rèn)的 EmbeddedServletOptions。

  • errorOnUseBeanInvalidClassAttribute 當(dāng) useBean 行為中的類屬性值不是合法的 bean 類時(shí),Jasper 是否彈出一個(gè)錯(cuò)誤?布爾值,默認(rèn)為 true。

  • fork Ant 是否應(yīng)該分叉(fork)編譯 JSP 頁面,以便在單獨(dú)的 JVM 中執(zhí)行編譯?布爾值,默認(rèn)為 true。

  • genStringAsCharArray 為了在一些情況下提高性能,是否應(yīng)將文本字符串生成字符數(shù)組?默認(rèn)為 false

  • ieClassId 使用 標(biāo)記時(shí),被送入 IE 瀏覽器中的類 ID 值。默認(rèn)值為:clsid:8AD9C840-044E-11D1-B3E9-00805F499D93。

  • javaEncoding 用于生成 Java 源文件的 Java 文件編碼。默認(rèn)為 UTF-8。

  • keepgenerated 對于每個(gè)頁面所生成的 Java 源代碼,應(yīng)該保留還是刪除?布爾值,默認(rèn)為 true(保留)。

  • mappedfile 為便于調(diào)試,是否應(yīng)該生成靜態(tài)內(nèi)容,每行輸入都帶有一個(gè)打印語句?布爾值,默認(rèn)為 true。

  • maxLoadedJsps Web 應(yīng)用所能加載的 JSP 的最大數(shù)量。如果超出此數(shù)目,就卸載最近最少使用的 JSP,以防止任何時(shí)刻加載的 JSP 數(shù)目不超過此限。0 或負(fù)值代表沒有限制。默認(rèn)為 -1。

  • jspIdleTimeout JSP 在被卸載前,處于空閑狀態(tài)的時(shí)間(以秒計(jì))。0 或負(fù)值代表永遠(yuǎn)不會(huì)卸載。默認(rèn)為 -1

  • modificationTestInterval 自上次檢查 JSP 修改起,造成 JSP(以及從屬文件)沒有被檢查修改的指定時(shí)間間隔(以秒計(jì))。取值為 0 時(shí),每次訪問都會(huì)檢查 JSP 修改。只用于開發(fā)模式下。默認(rèn)為 4 秒。

  • recompileOnFail 如果 JSP 編譯失敗,是否應(yīng)該忽略 modificationTestInterval,下一次訪問是否觸發(fā)重新編譯的嘗試?只用在開發(fā)模式下,并且默認(rèn)是禁止的,因?yàn)榫幾g會(huì)使用大量的資源,是極其昂貴的過程。

  • scratchdir 編譯 JSP 頁面時(shí)應(yīng)該使用的臨時(shí)目錄(scratch directory)。默認(rèn)為當(dāng)前 Web 應(yīng)用的工作目錄。

  • suppressSmap 是否禁止 JSR45 調(diào)試時(shí)生成的 SMAP 信息?truefalse,缺省為 false。

  • trimSpaces 是否應(yīng)清除模板文本中行為與指令之間的的空格?默認(rèn)為 false。

  • xpoweredBy 是否通過生成的 servlet 添加 X-Powered-By 響應(yīng)頭?布爾值,默認(rèn)為 false。

Eclipse JDT 的 Java 編譯器被指定為默認(rèn)的編譯器。它非常先進(jìn),能夠從 Tomcat 類加載器中加載所有的依賴關(guān)系。這將非常有助于編譯帶有幾十個(gè) JAR 文件的大型安裝。在較快的服務(wù)器上,還可能實(shí)現(xiàn)以次秒級(jí)周期對大型 JSP 頁面進(jìn)行重新編譯。

通過配置上述編譯器屬性,之前版本 Tomcat 所用的 Apache Ant 可以替代新的編譯器。

已知問題

bug 39089報(bào)告指出,在編譯非常大的 JSP 時(shí),已知的 JVM 問題 bug 6294277 可能會(huì)導(dǎo)致出現(xiàn) java.lang.InternalError: name is too long to represent 異常。如果出現(xiàn)這一問題,可以采用下列辦法來解決:

  • 減少 JSP 大小。
  • suppressSmap 設(shè)為 true,禁止生成 SMAP 信息與 JSR-045 支持。

生產(chǎn)配置

能做的最重要的 JSP 優(yōu)化就是對 JSP 進(jìn)行預(yù)編譯。但這通常不太可能(比如說,使用 jsp-property-group 功能時(shí))或者說不太實(shí)際,這種情況下,如何配置Jasper Servlet 就變得很關(guān)鍵了。

在生產(chǎn)級(jí) Tomcat 服務(wù)器上使用 Jasper 2 時(shí),應(yīng)該考慮將默認(rèn)配置進(jìn)行如下這番修改:

  • development 針對 JSP 頁面編譯,禁用訪問檢查,可以將其設(shè)為 false。
  • genStringAsCharArray 設(shè)定為 true 可以生成稍微更有效率的字符串?dāng)?shù)組。
  • modificationTestInterval 如果由于某種原因(如動(dòng)態(tài)生成 JSP 頁面),必須將 development 設(shè)為 true,提高該值將大幅改善性能。
  • trimSpaces 設(shè)為 true 可以去除響應(yīng)中的無用字節(jié)。

應(yīng)用編譯

使用 Ant 是利用 JSPC 編譯 Web 應(yīng)用的首選方式。注意在預(yù)編譯 JSP 頁面時(shí),如果 suppressSmapfalse,而 compile 為 true,則 SMAP 信息只能包含在最后的類中。使用下面的腳本來預(yù)編譯 Web 應(yīng)用(在 deployer 下載中也包含類似的腳本)。

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

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

   <target name="jspc">

    <jasper
             validateXml="false"
             uriroot="${webapp.path}"
             webXmlFragment="${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"
           optimize="off"
           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>

下面的代碼可以用來運(yùn)行該腳本(利用 Tomcat 基本路徑與指向應(yīng)被預(yù)編譯 Web 應(yīng)用的路徑來取代令牌)

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

然后,必須在 Web 應(yīng)用部署描述符文件中添加預(yù)編譯過程中生成的 servlet 的聲明與映射。將 ${webapp.path}/WEB-INF/generated_web.xml 插入 ${webapp.path}/WEB-INF/web.xml 文件中合適的位置。使用 Manager 重啟 Web 應(yīng)用,測試應(yīng)用,以便驗(yàn)證應(yīng)用能正常使用預(yù)編譯 servlet。利用Web 應(yīng)用部署描述符文件中的一個(gè)適當(dāng)?shù)牧钆?,也能使?Ant 過濾功能自動(dòng)插入生成的 servlet 聲明與映射。這實(shí)際上就是 Tomcat 所分配的所有 Web 應(yīng)用能作為構(gòu)建進(jìn)程中的一部分而自動(dòng)編譯的原理。

在 Jasper 任務(wù)中,還可以使用選項(xiàng) addWebXmlMappings,它可以將 ${webapp.path}/WEB-INF/web.xml 中的當(dāng)前 Web 應(yīng)用部署描述符文件自動(dòng)與 ${webapp.path}/WEB-INF/generated_web.xml 進(jìn)行合并。當(dāng)你想在 JSP 頁面中使用 Java 6 功能時(shí),添加下列 javac 編譯器任務(wù)屬性:source="1.6" target="1.6"。對于動(dòng)態(tài)應(yīng)用而言,還可以使用 optimize="on" 進(jìn)行編譯,注意,不用帶調(diào)試信息:debug="off"。

當(dāng)首次出現(xiàn) jsp 語法錯(cuò)誤時(shí),假如你不想停止 jsp 生成,可以使用 failOnError="false"showSuccess="true",將所有成功生成的 jsp to java 打印出來。這種做法有時(shí)非常有用,比如當(dāng)你想要在 ${webapp.path}/WEB-INF/src 中清除生成的 java 源文件以及 ${webapp.path}/WEB-INF/classes/org/apache/jsp 中的編譯 jsp 的 servlet 類時(shí)。

提示

  • 當(dāng)你換用另一版本的 Tomcat 時(shí),需要重新生成和編譯 JSP 頁面。
  • 在服務(wù)器運(yùn)行時(shí)使用 Java 系統(tǒng)屬性,通過設(shè)定 org.apache.jasper.runtime.JspFactoryImpl.USE_POOL=false 禁用 PageContext 池化,利用 org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER=true 限制緩存。注意,改變默認(rèn)值可能會(huì)影響性能,但這種情況跟具體的應(yīng)用有關(guān)。

優(yōu)化

Jasper 還提供了很多擴(kuò)展點(diǎn),能讓用戶針對具體的環(huán)境而優(yōu)化行為。

標(biāo)簽插件機(jī)制就是首先要談到的一個(gè)擴(kuò)展點(diǎn)。對于提供給 Web 應(yīng)用使用的標(biāo)簽處理器而言,它能提供多種替代實(shí)現(xiàn)。標(biāo)簽插件 通過位于 WEB-INFtagPlugins.xml 進(jìn)行注冊。Jasper 本身還包含了一個(gè) JSTL 的范例插件。

表達(dá)式語言(EL,Expression Language)解釋器則是另外一個(gè)擴(kuò)展點(diǎn)。通過 ServletContext 可以配置替代的 EL 解釋器。可以參看 ELInterpreterFactory Java 文檔來了解如何配置替代的 EL 解釋器。