JSP运行原理分析

JSP运行原理分析

我们在开发Java Web的过程中,可能有过这样的疑问,Tomcat是一个Servlet运行环境(容器),所有经过Tomcat的请求都是有一个servlet来处理的。servlet是一个Java类,可是jsp不是。那jsp又是怎么在Tomcat里面运行的呢?事实上,JSP是Servlet的一种特殊形式,每个JSP页面就是一个Servlet实例——JSP页面由系统编译成Servlet,Servlet再负责响应用户请求。JSP其实也是Servlet的一种简化,使用JSP时,其实还是使用Servlet,因为Web应用中的每个JSP页面都会由Servlet容器生成对应的Servlet。根据上面的分析,我们又有一个疑问:为什么说jsp就是一个Servlet,是根据什么来判定的呢?

  1. 为什么说jsp是Servlet?

首先我们在IntelljIdea里面编写一个简单的test.jsp页面

《JSP运行原理分析》

当启动Tomcat后,可以在Tomcat的\work\Catalina\localhost\ROOT\org\apache\jsp目录下找到如下文件《JSP运行原理分析》

这两个文件便是test.jsp经过系统编译生成的对应的 .java文件和 .class文件,我们打开test_jsp.java文件《JSP运行原理分析》

可以看到,这个test_jsp类继承了HttpJspBase这个类以及实现了org.apache.jasper.runtime.JspSourceDependent与org.apache.jasper.runtime.JspSourceImports这两个接口,我们知道判定一个类是Servlet的方法是看这个类是否间接或直接实现了Servlet接口,所以我们要看test_jsp这个类是否间接或直接实现了该接口,这里它并没有直接实现Servlet接口,所以现在我们还不能从这里看出test_jsp这个类就是一个Servlet,我们便可以猜想,会不会是HttpJspBase这个类实现了此接口呢。于是我们进一步分析HttpJspBase这个类的继承结构。

1.1HttpJspBase继承结构

 我们去查看HttpJspBase类的源码《JSP运行原理分析》

从上面就可以看出,该类继承了HttpServlet,我们之前便知道HttpServlet间接实现了Servlet接口。如果不知道的我们可以在IntelljIdea里面将鼠标定位在HttpJspBase上面按住ctrl+alt+u查看他的继承关系图:《JSP运行原理分析》

图 1-1 HttpJspBase继承关系

到这里我们便能清晰的知道为什么说jsp是一个Servlet了。

  1. Tomcat是如何处理jsp文件的?

经过上面的分析,我们已经知道了jsp就是一个Servlet。那jsp又是如何转换成Servlet的呢?我们在学习以前的学习中知道了我们写的每一个Servlet都需要在web.xml 文件里面的去做配置,这样浏览器才能访问得到这个Servlet。可是现在这个test.jsp并没有在我们项目的web.xml里面做任何配置,那浏览器是怎么访问到jsp页面的呢?回答这个问题之前我们先来了解一下Tomcat如何响应静态资源。

2.1 Tomcat如何响应静态资源?

2.1.1、全局web.xml解析

本质上讲,Tomcat对于所有的静态资源会做统一处理。也就是在所有你没有配置URL匹配的地方,Tomcat这个全局统一处理的配置就开始接管工作了。在Tomcat的conf目录下面我们可以看到有一个web.xml文件,打开后你会发现这样的说明:《JSP运行原理分析》

在向下你会看到关于这个全局处理的Servlet声明,如下图《JSP运行原理分析》

这个DefaultServlet的servlet-mapping是这样配置的:《JSP运行原理分析》

到这里不禁有人会问,既然url-pattern 配置的是  / ,那不就应该可以响应所有的请求了吗?其实上面的图中已经给出了解释,事实上这是匹配所有你没有定义的Servlet-mapping的请求。之所以自己定义的Servlet可以优先生效,则是因为Tomcat内的Servlet   的mapping配置是严格按照声明顺序初始化,并按此顺序响应请求,一层层按此比对,有一个可以响应请求,就用其处理。有相关疑问可以参考一下博文:

http://k1121.iteye.com/blog/1564241

我们简单总结一下:所有经过Tomcat的请求都是有一个servlet来处理的。如果一个请求没有匹配到任何应用指定的servlet,那么就会流到Tomcat的默认的servlet来,这个Servlet名字叫做DefaultServlet,DefaultServlet是配置在/conf/web.xml里面。

2.2、Tomcat如何响应jsp请求?

上一节我们了解到Tomcat使用DefaultServlet处理所有的静态资源。这一节我们来看一个jsp请求又是怎么被响应的。同DefaultServlet类似,jsp的处理也不需要我们单独配置,而是在/conf/web.xml中做为全局配置存在。其对应的处理类为JspServlet,用于处理所有的jsp请求。同样我们打开/conf/web.xml,可以看到以下代码与注释

《JSP运行原理分析》

《JSP运行原理分析》

通过看注释我们便对该配置的作用一目了然,往下看我们会看到JspServlet的mapping配置,其url-pattern为*.jsp和*.jspx。所以它可以拦截所有的jsp请求并作出相应的反应。

《JSP运行原理分析》

到这里我们便知道了为什么浏览器在我们自己没对jsp文件做任何配置的情况下依旧能访问的原因。

2.3、jsp如何转换成Servlet?

在文章开头我们知道当Tomcat启动过后,一个xxx.jsp文件会在\org\apache\jsp目录下生成相应的xxx_jsp.java文件与xxx_jsp.class文件,打开我们之前已经生成的test_jsp.java 文件,这个文件结构如下图所示:

《JSP运行原理分析》《JSP运行原理分析》

主要的转换动作是在方法_japService()中实现的,如下的Servlet类的代码截图可以看出,其中插入了session、application等对象的初始化,这几个对象都是通过页面级别的对象pageContext获取到的。

《JSP运行原理分析》  

页面中的java代码去哪儿了呢,转换过程中,HTML页面元素内容可以理解为通过out.write()直接输出给前端页面,java代码(<%%>包含的内容)直接去掉<%%>写到类中执行。部分代码截图如下。

《JSP运行原理分析》

图中红色方框内的内容就是我们在jsp页面中<% %>中的Java代码。在转化中直接去除<% %>后放到类代码中,而其余的可以理解为直接out.write()输出给前端页面。至此我们便解释了Tomcat如何处理jsp文件的问题。

3.总结

本文对jsp的运行原理进行了详细的分析。我们可以得出下面的流程图:

《JSP运行原理分析》

图3-1 jsp页面工作原理图

根据上面的JSP页面工作原理图,可以得到如下结论:

    — JSP文件必须在JSP服务器内运行。

    — JSP文件必须生成Servlet才能执行。

JSP和Servlet会有如下转换:

    - JSP页面的静态内容、JSP脚本都会转换成Servlet的xxxService()方法,类似于自行创建Servlet时service()方法。

    - JSP声明部分,转换成Servlet的成员部分。所有JSP声明部分可以使用private,protected,public,static等修饰符,其他地方则不行。

    - JSP的输出表达式(<%= ..%>部分),输出表达式会转换成Servlet的xxxService()方法里的输出语句。

    - 九个内置对象要么是xxxService()方法的形参,要么是该方法的局部变量,所以九个内置对象只能在JSP脚本和输出表达式中使用。

    原文作者:zcczero
    原文地址: https://blog.csdn.net/zcczero/article/details/84029114
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞