昨天花了很多時間弄清了JSP的運行原理,總的來說,JSP就是封裝好了的Servlet。不信的話請往下看:
首先你得弄清楚為什麼尾碼名為jsp的檔案就能運行,原因很簡單,因為Tomcat已經配置好了,設定檔是Tomcat的conf目錄下的web.xml,開啟該檔案找到如下代碼:
1 <servlet-mapping>2 <servlet-name>jsp</servlet-name>3 <url-pattern>*.jsp</url-pattern>4 </servlet-mapping>5 <servlet-mapping>6 <servlet-name>jsp</servlet-name>7 <url-pattern>*.jspx</url-pattern>8 </servlet-mapping>
這裡就是Tomcat配置好的,由上面的URL可以知道,尾碼名無論是jsp還是jspx都可以運行,甚至還可以自己更改,比如把*.jspx改成*.aaa,在Tomcat下的aaa檔案就能被運行。這是問什麼呢?<url-pattern>*.jsp</url-pattern>這一句就是配置URL的,只要URL中輸入的是jsp檔案,就會通過<servlet-name>jsp</servlet-name>,找到名為jsp的servlet,web.xml中還有這麼一段代碼:
1 <servlet> 2 <servlet-name>jsp</servlet-name> 3 <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> 4 <init-param> 5 <param-name>fork</param-name> 6 <param-value>false</param-value> 7 </init-param> 8 <init-param> 9 <param-name>xpoweredBy</param-name>10 <param-value>false</param-value>11 </init-param>12 <load-on-startup>3</load-on-startup>13 </servlet>
然後由servlet名找到servlet-class,即org.apache.jasper.servlet.JspServlet,JspServlet就是一個Servlet,它繼承了HttpServlet,所以jsp檔案能夠被運行。JspServlet類可以到Tomcat源檔案裡面去找,這裡不再詳講。
然後再講一講JSP的運行過程,當jsp檔案第一次被運行時它會被編譯成一個java檔案,然後再將這個java檔案編譯成class檔案(這些檔案放在tomcat的work目錄下)。要注意的是一個jsp檔案只能被編譯一次,也就是第一次啟動並執行時候被編譯,以後只要這個Jsp檔案沒有修改就不會再編譯了。比如說在tomcat裡面建立了一個demo.jsp,當這個jsp被啟動並執行時候就會被編譯成demo_jsp.java和demo_jsp.class。demo_jsp這個類繼承了HttpJspBase,HttpJspBase也是一個servlet,它繼承了HttpServlet,它的代碼如下:
1 package org.apache.jasper.runtime; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletConfig; 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse;10 import javax.servlet.jsp.HttpJspPage;11 import javax.servlet.jsp.JspFactory;12 13 import org.apache.jasper.compiler.Localizer;14 15 /**16 * This is the super class of all JSP-generated servlets.17 *18 * @author Anil K. Vijendran19 */20 public abstract class HttpJspBase 21 extends HttpServlet 22 implements HttpJspPage 23 24 25 {26 27 protected HttpJspBase() {28 }29 30 public final void init(ServletConfig config) 31 throws ServletException 32 {33 super.init(config);34 jspInit();35 _jspInit();36 }37 38 public String getServletInfo() {39 return Localizer.getMessage("jsp.engine.info");40 }41 42 public final void destroy() {43 jspDestroy();44 _jspDestroy();45 }46 47 /**48 * Entry point into service.49 */50 public final void service(HttpServletRequest request, HttpServletResponse response) 51 throws ServletException, IOException 52 {53 _jspService(request, response);54 }55 56 public void jspInit() {57 }58 59 public void _jspInit() {60 }61 62 public void jspDestroy() {63 }64 65 protected void _jspDestroy() {66 }67 68 public abstract void _jspService(HttpServletRequest request, 69 HttpServletResponse response) 70 throws ServletException, IOException;71 }
HttpJspBase這個類重寫了HttpServlet的service方法,而沒有重寫doGet()或者doPost()(通過URL啟動並執行預設是GET方式提交),因為首先調用的是service方法,而這個方法裡面又調用了_jspService()方法,HttpJspBase類中_jspService()方法是抽象方法,但是demo1_jsp這個類重寫了這個方法,所以就調用了demo1_jsp類中的_jspService()方法。以上就足以證明,JSP就是servlet了。
JSP中可以直接寫HTML標籤,又可以直接嵌入JAVA程式,java程式段寫在<% %>或者<%! %>裡面,但是寫在<% %>和寫在<%! %>裡又有什麼不同呢?<%! %>裡面是定義變數或者函數用的,寫在這裡面的會定義成demo1_jsp類中的成員變數或成員函數。而寫在<% %>裡面的則在_jspService()方法裡直接輸出了。