之前一直说的是Servlet,但是由于只是做一个Demo,并没有完全显示一个界面,所以它的两个缺点没有显示出来:
- 所有的HTML标签和文本都必须使用一个字符串形式通过ServletResponse的实例写出去;
- 所有的文本和样式必须得进行硬编码,也就是说如果你想稍微更改一下前端的显示的话,必须得重新编译Servlet实例;
针对这两个问题,提出了jsp这种技术,一般来说jsp有点像HTML文件,但是可以看到里面还有一些其他的元素,这就是java代码,但是相对于Servlet,它就是一个文本文件,不需要进行编译(其实是你没有看见而已),也就是说当你新添加一个JSP页面时不需要重启Servlet容器,并且该页面文件可以使用任何的文本编辑器编辑。JSP页面一般是在JSP容器中运行的,Servlet容器一般也是JSP容器,所以说Tomcat也可以充当JSP容器。
一、 请求JSP页面
对JSP页面的请求在本质上和请求一个Servlet是类似的,但是我们上面提到JSP页面的一大优点就是不需要编译,其实严格来说这是不对的,它只是不需要静态编译,也就是在正式部署运行之前是不需要编译的,但是在web应用部署运行之后则会动态地进行转换为servlet类并且编译这个类。
- 当第一次请求JSP页面时,会将转换成一个页面实现类,转换的工作是由servlet容器完成的,所生成的servlet的名称由servlet容器决定,如果转换错误则会发出错误到客户端;如果转换成功则会进一步被servlet容器编译(此处是动态编译)成servlet类,之后容器加载和实例化该类,并执行相应的生命周期方法;
- 对该页面的后续请求,servlet容器也不傻,每次都转换它也累,所以它会检查该JSP页面自从上一次转换后是否发生修改,如果修改过则会重新转换、编译并执行,如果没有则执行内存中已经存在的JSP类实例。
从上述说明中可以看到,对某个JSP页面的第一次请求是比较耗费时间的,有没有解决办法呢?当然有了!!
- 配置应用程序启动时就转换和编译所有的JSP页面,而不是在接收第一次请求才做这些工作;
- 预先编译JSP页面,并将它们以servlet的形式进行部署;
关于这方面是有一些工具提供使用的,还有一些web服务器是提供这方面的配置的,这里就不细说了,但是我是使用的tomcat,没有找到这方面相关的配置,如果哪位大神指教一下,感激不尽啊!!
二、 JSP的本质分析
首先说一下和JSP相关的包,如下:
- javax.servlet.jsp:包含核心的接口和类,servlet容器使用这些接口和类将JSP页面转换成servlet,最重要的莫过于JspPage和HttpJspPage;
- javax.servlet.jsp.el:包含支持JSP中的EL表达式的相关的类和接口
- javax.servlet.jsp.tagext:包含用于开发定制标签的类型,也就是如果你想自己写一个标签必须用到这里的API;
- javax.el:为Unified EL提供API;
JSP转换生成的页面类必须实现或者间接实现javax.servlet.jsp.JspPage接口,不出你所料,这个接口继承了javax.servlet.Servlet接口,如下:
这样我们就可以相信了,JSP页面确实是一个Servlet(我没有胡诌!!)。为了直观一些,我们直接看JSP页面转换生成之后的servlet类,通过对比进一步解释JSP的本质,如下是一个JSP页面index.jsp:
<html>
<body>
<h2>Hello World!</h2>
</body>
</html>
可以看出这就是由普通的HTML标签组成的文本(你骗我,这不是JSP,这就是HTML),前面说过JSP页面其实就是由HTML元素和java代码组成的。
转换成对应的servlet,index_jsp.java如下,从名字可以看出jtomcat将jsp页面转换成servlet时的名称是由“名称_jsp”组成:
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/7.0.68
* Generated at: 2016-04-16 12:01:36 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.l