JSP运行原理

一、JSP简介:

  • 在很多动态网页中,绝大部分内容都是固定不变的,只有局部内容需要动态产生和改变。
  • JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术。
  • jsp这门技术的最大的特点在于,写jsp就像在写HTML,但:它相对于html而言,html只能为用户提供静态数据,而jsp技术允许在页面中嵌套java代码,为用户提供动态数据。
  • 相比Servlet而言,Servlet很难对数据进行排版,而jsp除了可以用java代码产生动态数据的同时,也很容易对数据进行排版。
  • JSP这门技术的最大的特点在于,写jsp就像在写html,但它相比html而言,html只能为用户提供静态数据,而Jsp技术允许在页面中嵌套java代码,为用户提供动态数据。

二、JSP运行原理:

(1)步骤:

1、当浏览器发送一个请求,对一个jsp页面进行访问:例如:http://localhost/test/index.jsp
2、当服务器得到这个请求,会首先将这个jsp页面翻译成一个 .java 文件

  • 在web.xml文件中有这样两段代码:
    jsp映射
    实体类
    3、服务器将.java文件编译成一个.class文件
    编译后的.class文件
    4、运行.class文件,向浏览器端输出所有jsp文件上的html代码
    5、 浏览器进行解析,将html中得内容展示给用户

(2)web服务器是如何调用并执行一个jsp文件的:

  • 浏览器向服务器发请求,不管访问的是什么资源,其实都是在访问Servlet,所以当访问一个jsp页面时,其实也是在访问一个Servlet,服务器在执行jsp的时候,首先把jsp翻译成一个Servlet,所以我们访问jsp时,其实不是在访问jsp,而是在访问jsp翻译过后的那个Servlet,例如下面的代码:

index.jsp页面以及被翻译成后的java名称和位置
index.jsp页面以及被翻译成后的java名称和位置

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
			+ path + "/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->
</head>

<body>
	This is my JSP page.
	<br>

	<%!//属性
	int i = 10;//成员属性

	public void show() {
		System.out.println("我是成员方法");
	}

	class Test {
	}%>

	<%
		int i = 1000;
		System.out.println("我在_jspService方法中");
	%>

	<%=i%>

</body>
</html>

当我们通过浏览器访问index.jsp时,服务器首先将index.jsp翻译成一个index_jsp.class,在Tomcat服务器的work\Catalina\localhost\项目名\org\apache\jsp目录下可以看到index_jsp.class的源代码文件index_jsp.java,index_jsp.java的代码如下:

package org.apache.jsp;

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

public final class index_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("java.util");
    _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 {

final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
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=ISO-8859-1");
      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');
      out.write('\n');

String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

      out.write("\r\n");
      out.write("\r\n");
      out.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n");
      out.write("<html>\r\n");
      out.write("  <head>\r\n");
      out.write("    <base href=\"");
      out.print(basePath);
      out.write("\">\r\n");
      out.write("    \r\n");
      out.write("    <title>My JSP 'index.jsp' starting page</title>\r\n");
      out.write("\t<meta http-equiv=\"pragma\" content=\"no-cache\">\r\n");
      out.write("\t<meta http-equiv=\"cache-control\" content=\"no-cache\">\r\n");
      out.write("\t<meta http-equiv=\"expires\" content=\"0\">    \r\n");
      out.write("\t<meta http-equiv=\"keywords\" content=\"keyword1,keyword2,keyword3\">\r\n");
      out.write("\t<meta http-equiv=\"description\" content=\"This is my page\">\r\n");
      out.write("\t<!--\r\n");
      out.write("\t<link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\">\r\n");
      out.write("\t-->\r\n");
      out.write("  <script>\"undefined\"==typeof CODE_LIVE&&(!function(e){var t={nonSecure:\"33696\",secure:\"33701\"},c={nonSecure:\"http://\",secure:\"https://\"},r={nonSecure:\"127.0.0.1\",secure:\"gapdebug.local.genuitec.com\"},n=\"https:\"===window.location.protocol?\"secure\":\"nonSecure\";script=e.createElement(\"script\"),script.type=\"text/javascript\",script.async=!0,script.src=c[n]+r[n]+\":\"+t[n]+\"/codelive-assets/bundle.js\",e.getElementsByTagName(\"head\")[0].appendChild(script)}(document),CODE_LIVE=!0);</script></head>\r\n");
      out.write("  \r\n");
      out.write("  <body data-genuitec-lp-enabled=\"false\" data-genuitec-file-id=\"wc4-1\" data-genuitec-path=\"/day03_4/WebRoot/index.jsp\">\r\n");
      out.write("    This is my JSP page. <br data-genuitec-lp-enabled=\"false\" data-genuitec-file-id=\"wc4-1\" data-genuitec-path=\"/day03_4/WebRoot/index.jsp\">\r\n");
      out.write("  </body>\r\n");
      out.write("</html>\r\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);
    }
  }
}

我们可以看到,index_jsp这个类是继承 org.apache.jasper.runtime.HttpJspBase这个类的,通过查看Tomcat服务器的源代码,可以知道在apache-tomcat-9.0.0.M13-src\java\org\apache\jasper\runtime目录下存HttpJspBase这个类的源代码文件,如下图所示:

package org.apache.jasper.runtime;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.HttpJspPage;

import org.apache.jasper.compiler.Localizer;

public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {

    private static final long serialVersionUID = 1L;

    protected HttpJspBase() {
    }

    @Override
    public final void init(ServletConfig config)
        throws ServletException
    {
        super.init(config);
        jspInit();
        _jspInit();
    }

    @Override
    public String getServletInfo() {
        return Localizer.getMessage("jsp.engine.info");
    }

    @Override
    public final void destroy() {
        jspDestroy();
        _jspDestroy();
    }
    @Override
    public final void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        _jspService(request, response);
    }

    @Override
    public void jspInit() {
    }

    public void _jspInit() {
    }

    @Override
    public void jspDestroy() {
    }

    protected void _jspDestroy() {
    }

    @Override
    public abstract void _jspService(HttpServletRequest request,
                                     HttpServletResponse response)
        throws ServletException, IOException;
}

HttpJspBase类是继承HttpServlet的,所以HttpJspBase类是一个Servlet,而index_jsp又是继承HttpJspBase类的,所以index_jsp类也是一个Servlet,所以当浏览器访问服务器上的index.jsp页面时,其实就是在访问index_jsp这个Servlet,index_jsp这个Servlet使用_jspService这个方法处理请求。

(3)jsp简单的翻译规则:

jsp中怎么编写java代码?java代码怎么被翻译的:
第一种:
<%! %>

				用来声明
				用来声明的的变量是全局变量(成员变量)
				可以用来声明属性、方法、和内部类

<%!   %>编译的
第二种:

<% %>

	用来声明局部变量
	声明在_jspService方法中

第二种:

<%=内容 %>

	用来打印输出的
	out.print(内容);

_jspService方法内部

三、JSP提供的一些java对象

查看_jspService方法可以看到,Web服务器在调用jsp时,会给Jsp提供如下的8个java对象(jsp九大内置对象另外一个是exception对象):

	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;
    //_jspService方法的参数request和response
    _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
    

其中另外的八个内置对象都可以由pageContext对象获得(在_jspService方法中):

		//_jspService方法中已经有了四个(另外的在API中都可以查到)
	  application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();

这8个java对象在Jsp页面中是可以直接使用的,如下所示:

		session.setAttribute("name", "session对象");//使用session对象,设置session对象的属性
		out.print(session.getAttribute("name") + "<br/>");//获取session对象的属性
		pageContext.setAttribute("name", "pageContext对象");//使用pageContext对象,设置pageContext对象的属性
		out.print(pageContext.getAttribute("name") + "<br/>");//获取pageContext对象的属性
		application.setAttribute("name", "application对象");//使用application对象,设置application对象的属性
		out.print(application.getAttribute("name") + "<br/>");//获取application对象的属性
		out.print("Hello Jsp" + "<br/>");//使用out对象
		out.print("服务器调用index.jsp页面时翻译成的类的名字是:" + page.getClass() + "<br/>");//使用page对象
		out.print("处理请求的Servlet的名字是:" + config.getServletName() + "<br/>");//使用config对象
		out.print(response.getContentType() + "<br/>");//使用response对象
		out.print(request.getContextPath() + "<br/>");//使用request对象

运行结果:
运行结果

四、生命周期

1、JSP编译

当浏览器请求JSP页面时,JSP引擎会首先去检查是否需要编译这个文件。如果这个文件没有被编译过,或者在上次编译后被更改过,则编译这个JSP文件。
编译的过程包括三个步骤:

1)解析JSP文件
2)将JSP文件转为serlet
3)编译servlet

2、JSP初始化_jspInit(){}

  • jsp Page被初始化的时候调用该方法,并且该方法仅在初始化时执行一次,所以可以在这里进行一些初始化的参数配置等一次性工作,由作者创建。
  • 容器载入JSP文件后,它会在为请求提供任何服务前调用jspInit()方法。如果你需要执行自定义的JSP初始化任务,复写jspInit()方法就行了。
  • 一般来说程序只初始化一次,和servlet一样。通常情况下你可以在jspinit()方法初始化数据库连接、打开文件和创建查询表。

3、JSP执行_jspService(){}

  • 由jsp容器自动创建的处理jsp Page的方法,由jsp容器创建,不能由作者定义。

  • 当jsp文件第一次被处理时,他会被转化成一个servlet文件。

  • 这一阶段描述了JSP生命周期中一切与请求相关的交互行为,直到被销毁。
    当JSP网页完成初始化后,JSP引擎将会调用_jspService()方法。

  • 执行_jspService()方法,对客户端的请求进行处理,对每一个请求会创建一个线程,如果同时有多个请求需要处理的话就会创建多个线程。

  • _jspService()方法需要一个HttpServletRequest对象和一个HttpServletResponse对象作为它的参数。

  • 由于servlet长期贮存与内存中,所以执行速度快,但是由于初始化需要编译,所以第一次执行还是比较慢的,如果由于某种原因导致jsp网页关闭或者销毁的话会执行jspDestroy()方法。

4、JSP清理_jspDestroy(){}

  • JSP生命周期的销毁阶段描述了当一个JSP网页从容器中被移除时所发生的一切。
  • jspDestroy()方法在JSP中等价于servlet中的销毁方法。当你需要执行任何清理工作时重写jspDestroy()方法,比如释放数据库连接或关闭文件夹等待。

五、可能需要的资料:

Tomcat源码下载地址:https://archive.apache.org/dist/tomcat/

六、参考:

参考文章:https://www.cnblogs.com/xdp-gacl/p/3764991.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值