Tomcat是如何将JSP代码编译成Servlet代码的?
来源:互联网 发布:淘宝网商城女童鞋 编辑:程序博客网 时间:2024/06/06 06:36
链接:https://www.zhihu.com/question/37962360/answer/74311244
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
由于包括大量的HTML标签、大量的静态文本及格式等,导致Servlet的开发效率极为低下。所有的表现逻辑,包括布局、色彩及图像等,都必须耦合在Java代码中,这的确让人不胜其烦。
JSP的出现弥补了这种不足,JSP通过在标准的HTML页面中插入Java代码,其静态的部分无须Java程序控制,只有那些需要从数据库读取并根据程序动态生成信息时,才使用Java脚本控制。
从表面上看,JSP页面已经不再需要Java类,似乎完全脱离了Java面向对象的特征。
事实上,JSP是Servlet的一种特殊形式,每个JSP页面就是一个Servlet实例——JSP页面由系统编译成Servlet,Servlet再负责响应用户请求。
JSP其实也是Servlet的一种简化,使用JSP时,其实还是使用Servlet,因为Web应用中的每个JSP页面都会由Servlet容器生成对应的Servlet。对于Tomcat而言,JSP页面生成的Servlet放在work路径对应的Web应用下。
看下面一个简单的JSP页面:
<!-- 表明此为一个JSP页面 --><%@ page contentType="text/html; charset=gb2312" language="java" %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><HTML> <HEAD> <TITLE>第一个JSP页面</TITLE> </HEAD> <BODY> <!-- 下面是Java脚本--> <%for(int i = 0 ; i < 10; i++) { out.println(i); %> <br> <%} %> </BODY></HTML>
当启动Tomcat之后,可以在Tomcat的Catalina/localhost/jsp/test/org/apache/jsp目录下找到如下文件(假如Web应用名为jsptest,上面JSP页的名为test1.jsp):test1_jsp.java和test1_jsp.class。
这两个文件都是Tomcat生成的,Tomcat根据JSP页面生成对应Servlet的Java文件及class文件。
下面是test1_jsp.java文件的源代码,这是一个特殊的Java类,是一个Servlet类:
//JSP页面经过Tomcat编译后默认的包(不同的servlet容器提供商生成的servlet文件是不同的)
package org.apache.jsp;import javax.servlet.*;import javax.servlet.http.*;import javax.servlet.jsp.*; //继承HttpJspBase类,该类其实是个HttpServlet的子类(jasper是tomcat的jsp engine)public final class test1_jsp extends org.apache.jasper.runtime.HttpJspBase implements org.apache.jasper.runtime.JspSourceDependent { private static java.util.Vector _jspx_dependants; public java.util.List getDependants() { return _jspx_dependants; } //用于响应用户的方法 public void _jspService(HttpServletRequest request, HttpServletResponse response) throws java.io.IOException, ServletException { //built-in objects(variavles) are created here. //获得页面输出流 JspFactory _jspxFactory = null; PageContext pageContext = null; HttpSession session = null; ServletContext application = null; ServletConfig config = null; //获得页面输出流 JspWriter out = null; //not PrintWriter. JspWriter is buffered defautly. Object page = this; JspWriter _jspx_out = null; PageContext _jspx_page_context = null; //开始生成响应 try { _jspxFactory = JspFactory.getDefaultFactory(); //设置输出的页面格式 response.setContentType("text/html; charset=gb2312"); 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("rn"); //下面输出HTML标签 out.write("<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">rn"); out.write("<HTML>rn"); out.write("<HEAD>rn"); out.write("<TITLE>first Jsp</TITLE>rn"); out.write("</HEAD>rn"); out.write("<BODY>rn"); //页面中的循环,在此处循环输出 for(int i = 0 ; i < 10; i++) { out.println(i); out.write("rn"); out.write("<br>rn"); } out.write("rn"); out.write("</BODY>rn"); out.write("</HTML>rn"); out.write("rn"); } catch (Throwable t) { if (!(t instanceof SkipPageException)) { out = _jspx_out; if (out != null && out.getBufferSize() != 0) out.clearBuffer(); if (_jspx_page_context != null) _jspx_page_context.handle PageException(t); } } finally { if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_ page_context); } }}
对比test1.jsp和test1_jsp.java文件,可得到一个结论:该JSP页面中的每个字符都由test1_jsp.java文件的输出流生成。
根据上面的JSP页面工作原理图,可以得到如下四个结论:
— JSP文件必须在JSP服务器内运行。
— JSP文件必须生成Servlet才能执行。
— 每个JSP页面的第一个访问者速度很慢,因为必须等待JSP编译成Servlet。
— JSP页面的访问者无须安装任何客户端,甚至不需要可以运行Java的运行环境,因为JSP页面输送到客户端的是标准HTML页面。
JSP和Servlet会有如下转换:
- JSP页面的静态内容、JSP脚本都会转换成Servlet的xxxService()方法,类似于自行创建Servlet时service()方法。
- JSP声明部分,转换成Servlet的成员部分。所有JSP声明部分可以使用private,protected,public,static等修饰符,其他地方则不行。
- JSP的输出表达式(<%= ..%>部分),输出表达式会转换成Servlet的xxxService()方法里的输出语句。
- 九个内置对象要么是xxxService()方法的形参,要么是该方法的局部变量,所以九个内置对象只能在JSP脚本和输出表达式中使用。// 不能在jsp Declaration中使用
<TOMCAT_HOME>/conf/web.xml这个文件,里面有这样一段 <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-mapping> <servlet-name>jsp</servlet-name> <url-pattern>*.jsp</url-pattern> </servlet-mapping>然后再去看看org.apache.jasper.servlet.JspServlet这个类,跟着就会看到org.apache.jasper.servlet.JspServletWrapper这个类jsaper包下的类就是解析JSP代码的类了
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
链接:https://www.zhihu.com/question/37962360/answer/76489736
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
&lt;img src="https://pic2.zhimg.com/491b546497950691b4ff12b472655e21_b.jpg" data-rawwidth="702" data-rawheight="368" class="origin_image zh-lightbox-thumb" width="702" data-original="https://pic2.zhimg.com/491b546497950691b4ff12b472655e21_r.jpg"&gt;
而整个生成的过程类似于将jsp中的内容翻译下,输出字符串到文件一样。
整个处理过程类似于下面这个样子,是我大概画的一个时序图。
&lt;img src="https://pic1.zhimg.com/57894e9d5fb4f55b0f13506dcc69fb34_b.png" data-rawwidth="1974" data-rawheight="805" class="origin_image zh-lightbox-thumb" width="1974" data-original="https://pic1.zhimg.com/57894e9d5fb4f55b0f13506dcc69fb34_r.png"&gt;
其中生成的文件你看到的类似下面这个样子:
&lt;img src="https://pic1.zhimg.com/ca14a719f4b2e1330194bb7f7fe77310_b.jpg" data-rawwidth="536" data-rawheight="596" class="origin_image zh-lightbox-thumb" width="536" data-original="https://pic1.zhimg.com/ca14a719f4b2e1330194bb7f7fe77310_r.jpg"&gt;
而相应的生成代码则是这样的:
private void generateCommentHeader() { out.println("/*"); out.println(" * Generated by the Jasper component of Apache Tomcat"); out.println(" * Version: " + ctxt.getServletContext().getServerInfo()); out.println(" * Generated at: " + timestampFormat.format(new Date()) + " UTC"); out.println(" * Note: The last modified time of this file was set to"); out.println(" * the last modified time of the source file after"); out.println(" * generation to assist with modification tracking."); out.println(" */"); }
再比如,生成类声明的代码大概是这个样子:
// Generate class declaration out.printin("public final class "); out.print(servletClassName); out.print(" extends "); out.println(pageInfo.getExtends()); out.printin(" implements org.apache.jasper.runtime.JspSourceDependent,"); out.println(); out.printin(" org.apache.jasper.runtime.JspSourceImports"); if (!pageInfo.isThreadSafe()) { out.println(","); out.printin(" javax.servlet.SingleThreadModel"); } out.println(" {"); out.pushIndent();
---------------------------------------------------------------------------------------------------------------------------------
有机会自己找一些例子来分析下
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
先把java代码和html代码通过解析,分离。然后new一个servlet,函数里面加jsp里的java代码,把一些变量的值跟html拼起来,作为response。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
看一下jvm类加载机制就知道了,tomcat是把jvm封装了一层,jsp编译后和servlet编译后是一样的,然后使用jvm加载进来
- Tomcat是如何将JSP代码编译成Servlet代码的?
- jsp编译成servlet
- 将UE4代码编译成32位的编辑器
- jsp编译成servlet文件的分析
- 将c代码编译成dll文件
- jsp和servlet的关系?答:jsp就是servlet,tomcat会把jsp编译成servlet,servlet就是一个java类,在tomcat下的work文件夹中
- c程序是如何编译成的
- JSP编译成servlet后的文件存放位置
- Winform 代码编辑器 --将字符串编译成dll
- 一个将目录内所有c代码分别编译成独立的out文件的Makefile
- Python代码编译成二进制文件
- jsp被编译成servlet,为什么修改jsp页面,不用重新启动tomcat?
- JSP编译成Servlet(三)JSP编译后的Servlet
- GCC——C程序是如何编译成的
- GCC-C程序是如何编译成的
- GCC——C程序是如何编译成的
- GCC—C程序是如何编译成的 -windows
- 把一些重要的代码编译成Lib或者dll
- 1089. Insert or Merge
- js跨域问题 常见的集中解决方案
- HDU 1829 A Bug's Life(并查集)
- Visual Studio 2010 实用功能总结
- Java数组-查表法-进制转换
- Tomcat是如何将JSP代码编译成Servlet代码的?
- Leetcode 282. Expression Add Operators
- 数据结构与算法学习(五)HashMap
- C++将10进制字符串转为16进制字符串
- break,continue,return,exit的区别
- NameCheap+DigitalOcean部署网站
- linux常用命令4-文件链接ln
- hdu 1325 Is It A Tree?(并查集)
- VS2010 运行速度加快方法