Jasper簡介
對於基於Jsp的web應用來說,我們可以直接在Jsp頁面中編寫Java代碼,添加第三方的標籤庫,以及使用EL表達式。但是無論經過何種形式的處理,最終輸出到客戶端的都是標準的HTML頁面(包含js,css..),並不包含任何的java相關的語法。也就是說,我們可以把Jsp看做是一種運行在服務端的腳本。那麼服務器是如何將Jsp頁面轉換爲HTML頁面的呢?
Jasper模塊是 Tomcat的Jsp核心引擎,我們知道jsp本質上是一個servlet。 Tomcat使用 jasper對Jsp語法進行解析,生成servlet並生成class字節碼,用戶在進行訪問jsp時,會訪問servlet,最終將訪問的結果直接響應在瀏覽器端。另外,在運行的時候, Jasper還會檢測Jsp文件是否修改,如果修改,則會重新編譯Jsp文件。
JSP編譯方式
運行時編譯
Tomcat並不會在啓動web應用的時候自動編譯jsp文件,而是在客戶端第一次請求時,才編譯需要訪問的jsp文件。
編譯過程
Tomcat在默認的web.xml中配置了一個org.apache.jasper.servlet.JspServlet,用於處理所有的.jsp或.jspx結尾的請求,該servlet實現的即是運行時編譯的入口。
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
JspServlet處理流程圖:
編譯結果
- 如果在tomcat/conf/web.xml中配置了參數scratchdir,則編譯後的結果,就會存儲在該目錄下。
<init-param>
<param-name>scratchdir</param-name>
<param-value>D:/tem/jsp/</param-name>
</init-param>
- 如果沒有配置該選項,則會將編譯後的結果,存儲在tomcat安裝目錄下的work/Catalina/localhost/Context。假設項目名稱爲jsp_demo_01,默認的目錄爲:work/Catalina/localhost/jsp_demo_01
- 如果使用的是idea開發工具集成tomcat訪問web工程中的jsp,編譯後的結果,存放在:
C:\Users\Administartor\.IntelliJIdea2019.1\system\tomcat\_project_tomcat\work\Catalina\localhost\jsp_demo_01_war_exploder\org\apache\jsp
預編譯
除了運行時編譯,我們還可以直接在web應用啓動時,一次性將web應用中的所有的Jsp頁面一次性編譯完成。在這種情況下,Web應用運行過程中,便可以不必再進行實時編譯,而是直接調用Jsp頁面對應的sexvlet完成請求處理,從而提升系統性能。
Tomcat提供了一個shell程序Jspc,用於支持Jsp預編譯,而且在 Tomcat的安裝目錄下提供了一個catalina- tasks.xml文件聲明瞭
Tomcat支持的Ant任務,因此,我們很容易使用ant來執行Jsp預編譯。(要想使用這種方式,必須得確保在此之前已經下載並安裝了
(Apache Ant)
JSP編譯原理
- 其類名爲 index_jsp,繼承自org.apache.Jasper.runtime.HttpjspBase,該類是HttpServlet的子類,所以jsp本質就是一個servlet。
- 通過屬性_ jspx_dependants保存了當前Jsp頁面依賴的資源,包含引入的外部的Jsp頁面、導入的標籤、標籤所在的jar包等,便於後續處理過程中使用(如重新編譯檢測,因此它以Map形式保存了每個資源的上次修改時間)。
- 通過屬性_jsp_import_packages存放導入的java包,默認導入javax.servlet,javax.servlet.http,Javax.servletJsp
- 通過屬性 _jspx_imports_classes存放導入的類,通過 import指令導入的 Dateformat、 SimpleDateFormat、Date都會包含在該集合中。 _jspx_imports_packages和 _jspx_imports_classes屬性主要用於配置EL引擎上下文。
- 請求處理由方法_ JspService完成,而在父類HttpJspBase中的 service方法通過模板方法模式,調用了子類的_jspService方法
- _jspService方法中定義了幾個重要的局部變量: page、context、 Session、application、 config、out、page。由於整個頁面的輸出有 Jspservice方法完成,因此這些變量和參數會對整個Jsp頁面生效。這也是我們爲什麼可以在JsP頁面使用這些變量的原因
- 指定文檔類型的指令(page)最終轉換爲response.setContentType()方法調用。