【摘要】:本节讲解JSP 在Web 服务器内部的运行机制,只有详细了解JSP 的内部运行机制,开发人员才能更加游刃有余地运用JSP 技术。图4.4JSP 文件的执行过程从整个过程中可以知道,当第一次加载JSP 页面时,因为要将JSP 文件转换为Servlet类,所以响应速度较慢。在JSP 执行期间,JSP 容器会检查JSP 文件,看是否有更新或修改。
本节讲解JSP 在Web 服务器内部的运行机制,只有详细了解JSP 的内部运行机制,开发人员才能更加游刃有余地运用JSP 技术。
Web 容器管理JSP 页面生命周期的两个阶段:转换阶段(translation phase)和执行阶段(execution phase)。当有一个对JSP 页面的客户请求到来时,JSP 容器检验JSP 页面的语法是否正确,将JSP 页面转换为Servlet 源文件,然后调用javac 工具类编译Servlet 源文件生成字节码文件(class 文件),这一阶段是转换阶段。接下来,Servlet 容器加载转换后的Servlet 类,实例化一个对象处理客户端的请求,在请求处理完成后,响应对象被JSP 容器接收,容器将HTML 格式的响应信息发送到客户端,这一阶段是执行阶段。整个过程如图4.4 所示。
图4.4 JSP 文件的执行过程
从整个过程中可以知道,当第一次加载JSP 页面时,因为要将JSP 文件转换为Servlet类,所以响应速度较慢。当再次请求时,JSP 容器就会直接执行第一次请求时产生的Servlet,而不会再重新转换JSP 文件,所以其执行速度和原始的Servlet 执行速度几乎相同。在JSP 执行期间,JSP 容器会检查JSP 文件,看是否有更新或修改。如果有更新或修改,JSP 容器会再次编译JSP 或Servlet;如果没有更新或修改,就直接执行前面产生的Servlet,这也是JSP 相对于Servlet 的好处之一。
在Tomcat 服务器中,只保留了这些临时生成的Servlet 源文件和class 文件,这些文件保存在Tomcat 根目录下的work 目录下。例如hello.jsp 对应的转化文件保存在Tomcat 服务器根目录下的“work\Catalina\localhost\ch05\org\apache\jsp”目录下。在Eclipse 中,选择对应的服务,点击右键选择【open】,或者直接双击,打开【overview】详情配置页面。
图4.5 overview 详情配置页面
在【overview】界面可以看到相关的服务配置信息,查看【Server Location】,其中有两个路径信息,一个【server path】是Tomact 服务路径,一个是【Deploy path】发布路径,根据Tomcat 服务路径和发布路径,可以找到工程发布的位置。
图4.6 Server Locations 路径信息
找到Tomcat 根目录,然后进入“work\Catalina\localhost”目录。在这个目录的子目录ch05\org\apache\jsp 下,可以看到两个文件:“hello_jsp.java”和“hello_jsp.class”,这两个文件就是在访问hello.jsp 文件时由Web 容器生成的。
下面看一下JSP 容器在后台针对hello.jsp 生成的Servlet 源文件。虽然JSP 页面转换为Servlet 是在后台由JSP 容器自动进行的,但通过阅读JSP 容器生成的源代码来了解JSP 背后运行的机制,将有助于更好地理解JSP 页面的运行,编写更加健壮、安全的JSP 页面。
hello_jsp.java 的完整代码如下:
从上述代码可以看出,_jspService()方法打印输出了HTML 页面,这些代码对应的是hello.jsp 文件中的代码。还看到在_jspService()方法中定义了一些对象变量,并分别对这些对象进行了初始化,这些代码都是由Web 容器自动产生的。也就是说,在JSP 页面中,可以直接使用这些服务器端对象。在以后的课程中,将对这些对象进行介绍。(www.chuimin.cn)
hello_jsp.java 继承了org.apache.jasper.runtime.HttpJspBase 类。
HttpJspBase 类的部分代码如下:
HttpJspBase 类实际上就是一个实现了HttpJspPage 接口的Servlet 类。在Servlet类的init()方法中调用_jspInit()方法,在Servlet 类的destory()方法中调用_jspDestroy()方法,在Servlet 类的service()方法中调用_jspService()方法。从Tomcat 提供的HttpJspBase 类可以看出,JSP 页面运行的底层仍然是Servlet技术。
HttpJspBase 是一个抽象类,它是Tomcat 提供的实现了HttpJspPage 接口的类。而HttpJspPage 接口又继承了JspPage 接口。在JSP2.0 规范中定义,JSP 页面转换后的Servlet 类必须实现javax.servlet.jsp.JspPage 接口(与 Servlet 类似,Servlet 类必须实现 javax.servlet.Servlet 接口), 该接口继承自javax.servlet.Servlet 接口。除了继承的方法外,JspPage 接口还定义了下面两个方法:
这个方法在JSP 页面初始化时被调用,它类似于Servlet 中的init()方法。可以在JSP 的声明元素中覆盖这个方法,以提供任何的初始化工作。
在JSP 页面将要被销毁时调用这个方法。它类似于Servlet 中的destroy()方法。也可以在JSP 的声明元素中覆盖这个方法,以提供任何的JSP 清除工作。
因为绝大多数情况下的JSP 页面都是使用HTTP 协议,所以JSP 页面转换后的Servlet类实际上必须实现javax.servlet.jsp.HttpJspPage 接口,该接口继承自JspPage接口。除了继承的方法外,HttpJspPage 接口只定义了一个方法:
这个方法对应于JSP 页面的主体(body)部分,它类似于Servlet 中的service()方法。这个方法由Web 容器实现,不应当提供该方法的实现。在hello_jsp.java 中,_jspService()方法的内容就是Web 容器实现的。
为了把JSP 转化Servlet 所涉及的接口与类之间的关系描述得更清楚,它们之间的继承和实现的关系如图4.8 所示。图中带箭头的实线表示继承关系,带箭头的虚线表示实现关系;标有的表明是一个接口,标有的表明是一个类。
图4.8 JSP 转化Servlet 的相关接口和类的关系图
上面所讲的接口和类之间的关系较复杂,最关键的内容是要知道JSP 从根本上来说就是Servlet,至于中间出现的这些接口和类,没有掌握也不会影响使用Servlet 与JSP进行编程。
相关推荐