您的位置 首页 java

一文弄懂Jasper引擎编译JSP文件的分析说明

一文弄懂Jasper引擎编译JSP文件的分析说明

基本概念

  • 对于基于 jsp Web 应用,可以在 JSP 页面直接编写 Java 代码,添加第三方库,使用 EL 表达式.但是最终输出到客户端浏览器的都是标准的 html 页面,包括 js,css 等等.并不包含 java 相关的语法 .JSP 可以看作是一种运行在服务器端的脚本,最终以 HTML 页面方式响应给客户端
  • 使用 tomcat 中的Jasper引擎将jsp文件转换为HTML页面文件:JSP 本质上是一个 Servlet Tomcat 使用 Jasper JSP 语法进行解析,生成 servlet 并生成 Class 字节码文件用户在访问 jsp 文件时,会访问转换后的 Servlet, 最终的访问结果以 HTML 页面的方式直接响应在浏览器端在运行过程中 ,Jasper 引擎会检测 jsp 文件是否修改,如果修改则重新编译 jsp 文件

编译方式

运行时编译

  • Tomcat 不会在启动 Web 应用时自动编译 JSP 文件,而是在客户端第一次请求时,才编译需要访问的 JSP 文件

编译过程

  • Tomcat 在默认的 web.xml 中配置了 org. apache .jasper.servlet.JspServlet, 用于处理所有的 .jsp .jspx 结尾的请求
  • JspServlet 的实现就是运行编译时的入口
 <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>
<url-pattern>.jspx</url-pattern>
</servlet-mapping>
复制代码  
  • JspServlet请求处理流程:

编译结果

  • 如果在 tomcat/conf/web.xml 中配置了参数 scratchdir, jsp 编译后的结果会输出到配置的目录下:
 <init-param>
<param-name>scratchdir</param-name>
<param-value>e:/jsp/</param-value>
</init-param>
复制代码  
  • 如果没有配置该选项,则 jsp 编译后的结果,将会存放在 Tomcat 的安装目录的 work/Catalina/localhost/ 目录下

预编译

  • 预编译: 直接在 web 项目启动时,一次性将 web 应用用的所有 jsp 页面一次性编译完成.这样在 web 项目运行过程中,可以不再需要实时编译,而是直接调用 jsp 页面对应的 servlet 完成请求处理,从而提升系统性能
  • 要想进行预编译,必须首先确保下载并安装了 Apache Ant
  • Tomcat 中提供了一个 shell 程序 JspC 用于支持 jsp 编译,而且在 Tomcat 安装目录下提供了一个 catalina-tasks.xml 文件声明了 Tomcat 支持的 Ant 任务,这样很容易使用 Ant 来执行 jsp 的预编译

编译原理

代码分析

  • 生成的 Java 文件的类名为 index_jsp.java, 继承自 org.apache.jasper.runtime.HttpJspBase, 该类是 HttpServlet 的子类.所以 jsp 的本质就是一个 servlet
  • 属性 _jspx_denpendants 保存了当前 jsp 页面依赖的资源,包含引入的外部 jsp 页面,导入的标签,标签所在的 jar 包.便于后续处理过程中使用. 比如以 Map 形式保存了每个资源的上次修改时间便于重新编译检测
  • 属性 _jspx_imports_packages 存放导入的 java 包,默认导入 javax .servlet, javax.servlet.http, javax.servlet.jsp
  • 属性 _jspx_imports_classes 存放导入的类 ,jsp 页面中通过 import 标签导入的类都会包含在该集合 . _jspx_import_packages _jspx_import_classes 属性主要用于配置 EL 引擎上下文
  • 请求处理由 _jspService 方法完成,在父类 HttpJspBase 中的 service 方法通过模板方法模式,调用了子类的 _jspService 方法
  • _jspService 方法中定义了几个重要的局部变量 : pageContext, Session , application, config, out, page. 因为整个页面的输出都是由 _jspService 方法完成,因此这些变量和参数会对整个 jsp 页面生效. 这个就是在 jsp 页面中能够使用变量的原因
  • jsp 页面中指定文档类型的 page 变标签的值最终作为 response.setContentType() 使用
  • 对于生成的 html 文件的静态内容,调用 out.write() 输出
  • 对于 <% ..%> 标签中的代码,直接转换为 Servlet 类中的代码,如果在代码中嵌入了静态文件,同样会调用 out.write() 输出

编译流程

  • Jasper 的编译流程主要包括代码生成和编译两部分

  • Compiler 通过一个 PageInfo 对象保存 jsp 页面编译过程中的各种配置. 这些配置可以是来自于 web 应用的初始化参数,也可以是来自于 jsp 页面的标签指令配置,比如 page, include
  • 调用 ParseController 解析标签指令节点,验证标签指令是否合法,同时将配置信息保存到 PageInfo 中,用于控制代码生成
  • 调用 ParseController 解析整个 jsp 页面,由于 jsp 是逐行解析,所以会对每一行创建一个具体的 Node 对象,比如静态文本 TemplateText, Java 代码 Scriptlet , 定制标签 CustomTag, Include 标签指令 IncludeDirective
  • 验证标签指令外的其余节点的合法性. 比如脚本,定制标签 ,EL 表达式等
  • 获取标签指令以外的其余节点的页面配置信息
  • 编译并加载当前 jsp 页面依赖的标签
  • 对于 jsp 页面的 EL 表达式,生成对应的映射函数
  • 生成 jsp 页面对应的 servlet 源代码
  • 代码生成完成后 ,Compiler 会生成 SMAP 信息. 如果配置生成了 SMAP 信息 ,Compiler 则会在编译阶段将 SMAP 信息写到 class 文件中
  • 在编译阶段 ,Compiler 的两个实现 AntCompiler JDTCompiler 分别调用相关框架的 API 进行源代码解析 AntCompiler 通过构造一个 Ant javac 任务完成编译 JDTCompiler 通过调用 org.eclipse.jdt.internal.compiler.Compiler 完成编译

文章来源:智云一二三科技

文章标题:一文弄懂Jasper引擎编译JSP文件的分析说明

文章地址:https://www.zhihuclub.com/182873.shtml

关于作者: 智云科技

热门文章

网站地图