前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入理解JSP(一)

深入理解JSP(一)

作者头像
算法与编程之美
发布2019-09-29 17:32:23
7230
发布2019-09-29 17:32:23
举报

本文首发于微信公众号:"算法与编程之美",欢迎关注,及时了解更多此系列文章。

在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页面

当启动Tomcat后,可以在Tomcat的\work\Catalina\localhost\ROOT\org\apache\jsp目录下找到如下文件:

这两个文件便是test.jsp经过系统编译生成的对应的 .java文件和 .class文件,打开test_jsp.java文件

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

于是我们进一步分析HttpJspBase这个类的继承结构。

我们去查看HttpJspBase类的源码

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

图 1-1 HttpJspBase继承关系

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

2 Tomcat处理JSP文件流程分析

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

DefaultServlet介绍

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

在向下你会看到关于这个全局处理的Servlet声明,如下图

这个DefaultServlet的servlet-mapping是这样配置的:

到这里不禁有人会问,既然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里面。

JspServlet介绍

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

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

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

JSP转化为Servlet

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

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

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

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

3 总结

本文对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脚本和输出表达式中使用。

where2go 团队


本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-09-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 算法与编程之美 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档