JSP的运行原理
昨天花了很多时间弄清了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. Vijendran 19 */ 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()方法里直接输出了。