Tomcat7的JSP编译分析
首先, 当一个jsp的请求发起后, 会由JspServlet进行接受(请求的流程会在后续文章里详细说明), 会调用其service方法, 解析获得该jsp的urlPath, 并在参数中确定是否预编译模式.
之后, 调用serviceJspFile方法, 当该jsp是第一次请求时, 会新实例化JspServletWrapper对象, 并将其加入JspRuntimeContext里. 以后会直接从JspRuntimeContext中取JspServletWrapper对象, KEY值为jspUrl.
代码如下:
而后, 调用JspServletWrapper的service方法.
以上就是jsp页面请求的流程.
觉得很奇怪吧, jsp的文件怎么就变成了servlet的class类了呢, 第一当然是将jsp变为java的源代码文件了.
jsp怎么变成.java文件的呢?
在JspServletWrapper的service方法中调用ctxt.compile(); ctxt就是JspCompilationContext编译上下文
该方法主要做了以下几件事:
1. 创建Compiler, 根据选项参数反射得到Compiler
tomcat7 提供使用Eclipse的JDT org.apache.jasper.compiler.JDTCompiler,
使用ANT的org.apache.jasper.compiler.AntCompiler
2. 移除旧的.java和.class文件.
3. 将jsp文件转换生产.java
4. 将生成的.java编译生成.class文件.
代码跟踪如下:
以上代码来自tomcat源码类org.apache.jasper.compiler.Compiler
再跟进jspCompiler.compile();
再次跟进String[] smap = generateJava(); 大家你一定很奇怪, 为什么结果是smap 呢? 请大家耐心看下去吧.
这里就要简单介绍一下JSR-45
JSR-45(Debugging Support for Other Languages)为那些非 JAVA 语言写成,却需要编译成 JAVA 代码,运行在 JVM 中的程序,提供了一个进行调试的标准机制。也许字面的意思有点不好理解,什么算是非 JAVA 语言呢?其实 JSP 就是一个再好不过的例子,JSR-45 的样例就是一个 JSP。
JSP的调试一直依赖于具体应用服务器的实现,没有一个统一的模式,JSR-45 针对这种情况,提供了一个标准的模式。我们知道,JAVA 的调试中,主要根据行号作为标志,进行定位。但是 JSP 被编译为 JAVA 代码之后,JAVA 行号与 JSP 行号无法一一对应,怎样解决呢?
JSR-45 是这样规定的:JSP 被编译成 JAVA 代码时,同时生成一份 JSP 文件名和行号与 JAVA 行号之间的对应表(SMAP)。JVM 在接受到调试客户端请求后,可以根据这个对应表(SMAP),从 JSP 的行号转换到 JAVA 代码的行号;JVM 发出事件通知前, 也根据对应表(SMAP)进行转化,直接将 JSP 的文件名和行号通知调试客户端。
当参数支持JSR-45则产生的smap就是jsp的行号与生产.java行号的对应关系.
待续...