Tomcat06——Jasper 引擎

1. 简介

        对于基于JSP的web应用来说,我们可以直接在JSP页面中编写java代码,添加第三方的标签库,以及使用EL表达式,但是无论经过何种形式的处理,最终输出到客户端的都是标准的HTML页面(包含JS,CSS。。。),并不包含任何java相关的语法,也就是说,我们可以把jsp看做是一种运行在服务器端的脚本,那么服务器如何将JSP转换成HTML页面了?

        Jasper模块是tomcat的JSP核心引擎,我们知道JSP的本质是一个Servlet,tomcat使用Jasper对JSP语法进行解析,生成Service并生成Class字节码,用户在访问jsp的时候,会访问Servlet,最终将访问的结果直接响应在浏览器。另外,在运行的时候,Jasper还会检测JSP文件是否被修改,如果被修改,则会重新编译JSP文件。

2. JSP编译方式

2.1 运行时编译

        tomcat并不会在启动web应用的时候自动编译JSP文件,而是在客户端第一次请求的时候,才编译需要访问的JSP文件。

2.1.1 编译过程

        tomcat在默认的web.xml中配置了一个org.apache.jasper.servlet.JspServlet,用于处理所以的.jsp或者.jspx结尾的请求

<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>default</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- The mappings for the JSP servlet -->
    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.jspx</url-pattern>
    </servlet-mapping>

2.1.2 案例演示

创建一个web项目,并编写JSP代码

1. 创建一个4.0的servlet的web工程,如图:

注意:该工程是一个4.0的servlet的web工程,可以使用注解

2. 在index.jsp页面中写脚本程序

<%@ page import="java.text.DateFormat" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
  <head>
    <title>hello</title>
  </head>
  <body>
      <%
          DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
          String dateStr = format.format(new Date());
      %>
  hello ,Java server page...
  <br/>
  <%= dateStr %>
  </body>
</html>

注意:暂时不需要写servlet,先运行看看效果,如图:

我们发现,浏览器返回了我们脚本程序中定义的时间字符串。

2.1.3 案例分析

        我们发现,我们在地址栏中并没有输入index.jsp,但是浏览器还是可以返回该页面的信息,这是因为,没有指定访问页面的时候,默认访问的就是当前工程下的index.jsp,当访问的是index.jsp的时候,这个时候,请求会被tomcat的JspServlet所拦截,然后JspServlet开始处理该请求。

JspServlet的处理流程图:

1. 首先用户在访问的时候,访问的是我们的JSP,访问这个请求到达服务端之后,服务端会去调用JSPServlet的service()来进行处理。

2. 在JSPServlet中调用service方法:

       2.1 service里面的逻辑首先获取jsp的文件路径

       2.2 判断当前是否为预编译请求

        2.3 执行serviceJspFile()方法

        2.4 获取JspServletWrapper对象

3. 获取到JspServletWrapper对象,去调用其service方法,对jsp文件进行源码的生成然后在进行编译,最终调用这个JSP生成的servlet来执行对应的请求。

2.1.4 源码跟踪分析

我们将我们的项目编译之后的目录复制到tomcat的工程的home/weapps下,如图:

启动源码程序,在浏览器输入网址http://localhost:8080/webTest/,浏览器正常返回,如图:

然后我们重新以debug模式开启tomcat源码项目,在JspServlet.java的service方法处打一个断点,如图:

我们在浏览器回车,程序走到断点处,jspUri=null,程序走到

jspUri = request.getServletPath();

这时候,jspUri=“/index.jsp”,这是因为,我们虽然没有指定index.jsp,但是在tomcat的web.xml的配置文件中有如下配置

<welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

程序会依次找index.html、index.htm、index.jsp这三个文件,如果找到了index.html,那么返回index.html,找到了index.jsp就返回index.jsp。

接着断点往下走,走到

boolean precompile = preCompile(request);

判断是否为预编译请求,然后调用serviceJSPService方法,将是否预编译返回值传过去,如图:

进入serviceJSPService,首先就是获取JspServletWrapper对象

JspServletWrapper wrapper = rctxt.getWrapper(jspUri);

拿到wrapper对象之后,再去调用其service方法

wrapper.service(request, response, precompile);

进入wrapper的service方法

if (options.getDevelopment() || mustCompile) {
      // The following sets reload to true, if necessary
      ctxt.compile();
      mustCompile = false;
}

在进入compile方法,执行JSPCompile.compile方法,如图:

在进入compile,

开始编译jsp

注意:generateJava生成java文件,generateClass生成class文件

编译结果存放在哪里了?

1)如果在tomcat/conf/web.xml中配置了参数scratchdir,则JSP编译后的结果,就会存储在该目录下。

<init-param>
    <param-name>scratchdir</param-name>
    <param-value>D:/tmp/jsp/</param-value>
</init-param>

2) 如果没有配置该选项,则会将编译结果存储在tomcat安装目录下的work/Catalina(Engine名称)/localhost(Host名称)/Context名称。假设项目名称为jsp_demo_01,那么,默认目录为:work/Catalina/localhost/jsp_demo_01

3) 如果使用的是idea开发根据集成tomcat访问web工程中的jsp,编译后的结果存放在idea的tomcat的work/Catalina(Engine名称)/localhost(Host名称)/Context名称中。

生成了java文件,生成了class字节码文件,然后回到JspServletWraper,如图:

接着运行,获取生成是字节码对象

 
 

接着执行index_jsp的service方法了

调用生成的servlet,将需要的信息通过out输出到浏览器,如图:

2.2 预编译

        预编译就是在web应用启动的时候,一次性的将web应用中的所有的JSP页面一次性的编译完成,在这种情况下,web应用运行过程中,便可以不必再进行实时编译,而是直接调用JSP页面对应的Servlet完成请求处理,从而提升系统性能。

       Tomcat提供了一个shell程序JspC,用于支持JSP预编译,而且在tomcat的安装目录下提供了一个Catalina-task.xml文件,声明了Tomcat支持的Ant任务,因此,我们很容易使用Ant来执行JSP预编译。(要使用这种方式,需要确保在此之前已经下载并安装了Apache Ant)。

发布了143 篇原创文章 · 获赞 7 · 访问量 4445

猜你喜欢

转载自blog.csdn.net/weixin_43318134/article/details/104072872