JavaWeb-05-JSP规范-04-JSP文件运行原理
JavaWeb-05-JSP规范-04-JSP文件运行原理
1.Http服务器调用JSP文件步骤
- Http服务器将JSP文件内容【编辑】为一个Servlet接口实现类(.java)
- Http服务器将Servlet接口实现类【编译】为class文件(.class)
- Http服务器负责创建这个class文件的实例对象,这个实例对象就是Servlet实例对象。
- 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);
}
}
可以得出:
- 该方法的参数列表是请求对象【request】和响应对象【response】
- 在jsp中编写的java代码和html代码都会被翻译到【_jspService】方法中去。
- 在jsp中编写的java代码会原封不动地翻译成java代码,
- 【<%int age = (int)request.getAttribute("key1");%>】直接翻译成【int age = (int)request.getAttribute("key1");】
- 在JSP文件中定义的java变量都是该方法内的局部变量
- 而HTML代码则会翻译成【out.write("<html标签>\r\n");】的形式。
- 在jsp中编写的java代码会原封不动地翻译成java代码,
- 该方法是使用输出流将数据写入到响应体内
- 在jsp页面中编写的java代码翻译到_jspService方法后,在被调用时,会在该方法内直接执行,然后通过输出流将执行结果写入响应体中。
- 在jsp页面中编写的html标签翻译到_jspService方法后,在被调用时,会通过输出流,原封不动地写入到响应体中。