详解JSP
JSP是J2EE标准之一,和ASP.NET中的aspx作用和开发类似,这篇博客我们通过一个简单的实例,看一下JSP的部署、执行原理及生命周期等。
新建
我们新建一个项目,按照Tomcat要求的基本文档结构,名为MyFirstJSP,在这个项目下新建一个JSP,名为HelloWorld.jsp,目的只是输出一行HelloWorld:
[html]
<html>
<head>
<title>login</title>
</head>
<body>
<% out.println("HelloWorld"); %>
</body>
<html>
<html>
<head>
<title>login</title>
</head>
<body>
<% out.println("HelloWorld"); %>
</body>
<html>
部署
JSP的部署,不像Servlet一样繁琐(可以参见博客博客《Tomcat下Servlet登录实例》),不需要修改配置文件,也不需要指定jsp的动作指向,按照上面的步骤新建完毕项目以后,打开Tomcat,输入
配置文件
打开Tomcat根目录下conf下的web.xml,可以发现以下配置:
[html]
<!-- The mapping for the JSP servlet -->
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
<!-- The mapping for the JSP servlet -->
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
现在我们把配置文件中的*.jspx修改为*.test,把我们的HelloWorld.jsp修改为HelloWorld.test,然后访问http://localhost:8080/MyFirstJSP/HelloWorld.test,执行结果为:
和上面相同,其实这个配置的意思是:把什么样的文件当做jsp来解析,此处也可以修改为其它格式。
可见,如果配置合理,拓展名对jsp执行无影响,那么jsp的执行原理是什么?我们继续看这个配置文件,可以发现如下配置:
[html]
<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>
<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>
可见,此配置的作用是找到处理jsp的类,经过比对代码,其实就是把jsp当做Servlet处理,当然只凭这个说服力不大,我们继续往下看。
进入D:\Program Files (x86)\apache-tomcat-6.0.33\work\Catalina\localhost\MyFirstJSP\org\apache\jsp下,发现如下的文档结构:
在此处会自动生成与之对应的java文件和类文件,因为刚才我们尝试了test的文件,所以此处也生成了对应的test的java和类文件。我们打开HelloWorld_jsp.java,找到主要的函数_jspService:
[java]
<SPAN style="FONT-FAMILY: SimSun">public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
JspWriter _jspx_out = null;
PageContext _jspx_page_context = null;
try {
response.setContentType("text/html");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("<html>\r\n");
out.write("\t<head>\r\n");
out.write("\t\t<title>login</title>\r\n");
out.write("\t</head>\r\n");
out.write("\t<body>\r\n");
out.write("\t\t\t");
out.println("HelloWorld");
out.write("\r\n");
out.write("\t</body>\r\n");
out.write("<html>");
} catch (Throwable t) {
if (!(t instanceof SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try { out.clearBuffer(); } catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}</SPAN>
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
JspWriter _jspx_out = null;
PageContext _jspx_page_context = null;
try {
response.setContentType("text/html");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("<html>\r\n");
out.write("\t<head>\r\n");
out.write("\t\t<title>login</title>\r\n");
out.write("\t</head>\r\n");
out.write("\t<body>\r\n");
out.write("\t\t\t");
out.println("HelloWorld");
out.write("\r\n");
out.write("\t</body>\r\n");
out.write("<html>");
} catch (Throwable t) {
if (!(t instanceof SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try { out.clearBuffer(); } catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
} 发现什么没有?这个函数的参数为HttpServletRequest和HttpServletResponse,可能的异常为ServletException;可见此处是把jsp当做了Servlet处理。
生命周期
jsp第一次加载会编译,所以比较慢,编译以后访问即不再变化(jsp文件不变前提),可以使用工具诸如Weblogic jspc对jsp进行预编译。
为了方便说明,我们找到Tomcat源文件HttpJspBase.java,打开这个文件,函数如下(省略本文章不需要的代码):[java] view plaincopyprint?
public abstract class HttpJspBase
extends HttpServlet
implements HttpJspPage
{
public final void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
_jspService(request, response);
}
public abstract void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException;
}
public abstract class HttpJspBase
extends HttpServlet
implements HttpJspPage
{
public final void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
_jspService(request, response);
}
public abstract void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException;
} 根据源码和简单解释一下这个过程:
客户端首先发出请求,Tomcat接收到请求
如上面配置文件所示,执行JspServlet的service()函数
如果jsp第一次被请求,则编译jsp为Servlet
因为Helloworld_jsp已经被编译为Servlet,以后的执行顺序和普通的Servlet一样先执行new()
再执行_jspService()
形成html,返回给浏览器
总结
既然jsp被编译后就是一个Servlet,为什么还要有jsp?jsp的出现在Servlet之后,目的就是简化Servlet的开发和部署。