JavaWeb-05-JSP规范-04-JSP文件运行原理

JavaWeb-05-JSP规范-04-JSP文件运行原理

1.Http服务器调用JSP文件步骤

  1. Http服务器将JSP文件内容【编辑】为一个Servlet接口实现类(.java)
  2. Http服务器将Servlet接口实现类【编译】为class文件(.class)
  3. Http服务器负责创建这个class文件的实例对象,这个实例对象就是Servlet实例对象。
  4. Http服务器通过调用Servelt实例对象调用_jspService方法,将jsp文件内容写入响应体。

2.验证

2.1创建网站文件

新建一个网站MyWeb,创建一个Servlet接口实现类【OneServlet】和一个JSP文件【one.jsp】。

2.2编写Servlet文件给JSP文件传值

在OneServlet里,重写doGet方法,将一个数字放入当前请求作用域对象中,然后通过请求转发方式,调用one.jsp文件。

package com.tsccg.controller;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Author: TSCCG
 * @Date: 2021/08/23 16:59
 */
public class OneServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setAttribute("key1",17);
        request.getRequestDispatcher("one.jsp").forward(request,response);
    }
}

2.3编写JSP文件

在one.jsp文件中,读取当前请求作用域对象中的数字,放入一个定义的变量【age】中。

然后编写一个判断语句,根据这个数字执行指定代码块。

<%--
  Created by IntelliJ IDEA.
  User: Admin
  Date: 2021/8/23
  Time: 16:07
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    int age = (int)request.getAttribute("key1");
    if(age >= 18) {
%>
        <center>
            <font style="color: green";font-size: 20px>您的年龄是:<%=age%>岁,是成年人</font>
            <br/>
            <font style="color: green";font-size: 20px>欢迎光临</font>
        </center>
<%
    } else {
%>
        <center>
            <font style="color: red";font-size: 20px>您的年龄是:<%=age%>岁,是未成年人</font>
            <br/>
            <font style="color: red";font-size: 20px>拒绝入内</font>
        </center>
<%
    }
%>

2.4运行JSP文件

开启服务器,通过浏览器访问OneServlet

当我们运行JSP文件时,Tomcat服务器会将JSP文件编辑成一个java文件,然后将其编译为一个class文件。

2.5定位JSP文件编译后文件位置

根据开启服务器时,控制台上第三行命令所显示的路径,找到目标位置。

C:\Users\Admin\AppData\Local\JetBrains\IntelliJIdea2020.1\tomcat\Unnamed_WebProject_7

然后进入work目录

一路到达jsp目录下,这里存放的java和class文件,都是由本次项目中的JSP文件被Tomcat服务器所编辑而来的

2.6查看被Tomcat编辑而来的java文件源码

将one_jsp.java拖进idea查看,代码如下

/*
 * Generated by the Jasper component of Apache Tomcat
 * Version: Apache Tomcat/9.0.45
 * Generated at: 2021-08-23 09:16:14 UTC
 * Note: The last modified time of this file was set to
 *       the last modified time of the source file after
 *       generation to assist with modification tracking.
 */
package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class one_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports {

  private static final javax.servlet.jsp.JspFactory _jspxFactory =
          javax.servlet.jsp.JspFactory.getDefaultFactory();

  private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;

  private static final java.util.Set<java.lang.String> _jspx_imports_packages;

  private static final java.util.Set<java.lang.String> _jspx_imports_classes;

  static {
    _jspx_imports_packages = new java.util.HashSet<>();
    _jspx_imports_packages.add("javax.servlet");
    _jspx_imports_packages.add("javax.servlet.http");
    _jspx_imports_packages.add("javax.servlet.jsp");
    _jspx_imports_classes = null;
  }

  private volatile javax.el.ExpressionFactory _el_expressionfactory;
  private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;

  public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
    return _jspx_dependants;
  }

  public java.util.Set<java.lang.String> getPackageImports() {
    return _jspx_imports_packages;
  }

  public java.util.Set<java.lang.String> getClassImports() {
    return _jspx_imports_classes;
  }

  public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
    if (_el_expressionfactory == null) {
      synchronized (this) {
        if (_el_expressionfactory == null) {
          _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
        }
      }
    }
    return _el_expressionfactory;
  }

  public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
    if (_jsp_instancemanager == null) {
      synchronized (this) {
        if (_jsp_instancemanager == null) {
          _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
        }
      }
    }
    return _jsp_instancemanager;
  }

  public void _jspInit() {
  }

  public void _jspDestroy() {
  }

  public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
      throws java.io.IOException, javax.servlet.ServletException {

    if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
      final java.lang.String _jspx_method = request.getMethod();
      if ("OPTIONS".equals(_jspx_method)) {
        response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
        return;
      }
      if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
        response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
        response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS");
        return;
      }
    }

    final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;


    try {
      response.setContentType("text/html;charset=UTF-8");
      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("\r\n");
      out.write("\r\n");

    int age = (int)request.getAttribute("key1");
    if(age >= 18) {

      out.write("\r\n");
      out.write("        <center>\r\n");
      out.write("            <font style=\"color: green\";font-size: 20px>您的年龄是:");
      out.print(age);
      out.write("岁,是成年人</font>\r\n");
      out.write("            <br/>\r\n");
      out.write("            <font style=\"color: green\";font-size: 20px>欢迎光临</font>\r\n");
      out.write("        </center>\r\n");

    } else {

      out.write("\r\n");
      out.write("        <center>\r\n");
      out.write("            <font style=\"color: red\";font-size: 20px>您的年龄是:");
      out.print(age);
      out.write("岁,是未成年人</font>\r\n");
      out.write("            <br/>\r\n");
      out.write("            <font style=\"color: red\";font-size: 20px>拒绝入内</font>\r\n");
      out.write("        </center>\r\n");

    }

      out.write('\r');
      out.write('\n');
    } catch (java.lang.Throwable t) {
      if (!(t instanceof javax.servlet.jsp.SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try {
            if (response.isCommitted()) {
              out.flush();
            } else {
              out.clearBuffer();
            }
          } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
        else throw new ServletException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}

2.7源码分析

2.7.1验证该类是否为Servlet接口实现类

由开头的类名定义可见,该类继承了HttpJspBase

public final class one_jsp extends org.apache.jasper.runtime.HttpJspBase

查阅api资料得知,HttpJspBase是一个抽象类,继承了HttpServlet。

由此可以得出结论:JSP文件运行时,会被Tomcat编辑为一个Servlet接口实现类。

2.7.2JSP将数据写入响应体的原理

在JSP被编辑后的源码中,有一个_jspService方法,如下:

public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
    throws java.io.IOException, javax.servlet.ServletException {

    if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
        final java.lang.String _jspx_method = request.getMethod();
        if ("OPTIONS".equals(_jspx_method)) {
            response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
            return;
        }
        if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
            response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
            response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS");
            return;
        }
    }

    final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;


    try {
        response.setContentType("text/html;charset=UTF-8");
        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("\r\n");
        out.write("\r\n");

        int age = (int)request.getAttribute("key1");
        if(age >= 18) {

            out.write("\r\n");
            out.write("        <center>\r\n");
            out.write("            <font style=\"color: green\";font-size: 20px>您的年龄是:");
            out.print(age);
            out.write("岁,是成年人</font>\r\n");
            out.write("            <br/>\r\n");
            out.write("            <font style=\"color: green\";font-size: 20px>欢迎光临</font>\r\n");
            out.write("        </center>\r\n");

        } else {

            out.write("\r\n");
            out.write("        <center>\r\n");
            out.write("            <font style=\"color: red\";font-size: 20px>您的年龄是:");
            out.print(age);
            out.write("岁,是未成年人</font>\r\n");
            out.write("            <br/>\r\n");
            out.write("            <font style=\"color: red\";font-size: 20px>拒绝入内</font>\r\n");
            out.write("        </center>\r\n");

        }

        out.write('\r');
        out.write('\n');
    } catch (java.lang.Throwable t) {
        if (!(t instanceof javax.servlet.jsp.SkipPageException)){
            out = _jspx_out;
            if (out != null && out.getBufferSize() != 0)
                try {
                    if (response.isCommitted()) {
                        out.flush();
                    } else {
                        out.clearBuffer();
                    }
                } catch (java.io.IOException e) {}
            if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
            else throw new ServletException(t);
        }
    } finally {
        _jspxFactory.releasePageContext(_jspx_page_context);
    }
}

可以得出:

  1. 该方法的参数列表是请求对象【request】和响应对象【response】
  2. 在jsp中编写的java代码和html代码都会被翻译到【_jspService】方法中去。
    1. 在jsp中编写的java代码会原封不动地翻译成java代码,
      • 【<%int age = (int)request.getAttribute(“key1”);%>】直接翻译成【int age = (int)request.getAttribute(“key1”);】
      • 在JSP文件中定义的java变量都是该方法内的局部变量
    2. 而HTML代码则会翻译成【out.write("<html标签>\r\n");】的形式。
  3. 该方法是使用输出流将数据写入到响应体内
    1. 在jsp页面中编写的java代码翻译到_jspService方法后,在被调用时,会在该方法内直接执行,然后通过输出流将执行结果写入响应体中。
    2. 在jsp页面中编写的html标签翻译到_jspService方法后,在被调用时,会通过输出流,原封不动地写入到响应体中。

3.总结Http服务器调用JSP文件流程图

参考博客:https://www.cnblogs.com/xdp-gacl/p/3764991.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TSCCG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值