目录
第五章 | 动态资源与Servlet
| 章节概述
| Tomcat与Servlet的 原理、关系
Tomcat的基本构成编辑
Server处理HTTP请求
Connector内部架构分析
Container内部架构分析
Tomcat的执行流程小结
| Servlet 概述、接口实现
Servlet的基本概述
实现Servlet接口并通过URL访问:四大步骤
IDEA一键生成Servlet实现类
| Servlet对象的 周期与load-on-startup
本文章属于后端全套笔记的第三部分
(更新中)【后端入门到入土!】Java+Servlet+JDBC+SSM+SpringBoot+SpringCloud 基础入门_m0_57265007的博客-CSDN博客一篇文章,后端入门到入土。包含 Java基础+高级、MySQL、JDBC、Servlet、SSM、SpringBoot、SpringCloud、项目 的笔记。https://blog.csdn.net/m0_57265007/article/details/127962617?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22127962617%22%2C%22source%22%3A%22m0_57265007%22%7D
第五章 | 动态资源与Servlet
| 章节概述
本章将学习
-
通过Tomcat的基本原理,引出Servlet的基本原理(理论基础)
-
掌握Servlet在IDEA中创建其实现类、注册配置实现类到Tomcat、部署、访问的一系列步骤。同时学会使用IDEA快速生成Servlet类的敲门
-
Servlet对象的生命周期、被创建的时机、load-on-time参数
-
HttpServletRequest 解析HTTP请求并发送给服务器
-
HttpServletResponse 响应HTTP请求
-
多Servlet间数据共享
-
多Servlet间调用规则
| Tomcat与Servlet的 原理、关系
Tomcat的基本构成
1、Tomcat中最顶层的容器是Server,代表着整个服务器,一个Server可以包含至少一个Service,用于具体提供服务。
2、Service主要包含两个部分:Connector和Container。 Tomcat 的心脏就是这两个组件,这两个组件的作用:Connector用于处理连接相关的事情,并提供Socket与Request和Response相关的转化;Container用于封装和管理Servlet,以及具体处理Request请求。
3、一个Tomcat中只有一个Server,一个Server可以包含多个Service,一个Service只有一个Container,但是可以有多个Connectors,因为一个服务可以有多个连接,如同时提供Http和Https链接,也可以提供向相同协议不同端口的连接。
4、多个 Connector 和一个 Container 就形成了一个 Service,有了 Service 就可以对外提供服务了,但是 Service 还要一个生存的环境,必须要有人能够给她生命、掌握其生死大权,那就非 Server 莫属了!所以整个 Tomcat 的生命周期由 Server 控制。另外,上述的包含关系或者说是父子关系,都可以在tomcat的conf目录下的server.xml配置文件中看出。
5、Server标签设置的端口号为8005(注意:Server标签的端口号8005用于监听Tomcat的Server接口;而Tomcat端口8080是用于监视来自外部的HTTP请求。两者是不一样的概念!),shutdown=”SHUTDOWN” ,表示在8005端口监听“SHUTDOWN”命令,如果接收到了就会关闭Tomcat。一个Server有一个Service,当然还可以进行配置,一个Service有多个,Service左边的内容都属于Container的,Service下边是Connector。
Server处理HTTP请求
1.用户在浏览器中输入该网址,请求被发送到本机端口8080,被在那里监听的Coyote HTTP/1.1 Connector获得;
2.Connector把该请求交给它所在的Service的Engine(Container)来处理,并等待Engine的回应;
3.Engine获得请求localhost/test/index.jsp,匹配所有的虚拟主机Host;
4.Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机),名为localhost的Host获得请求/test/index.jsp,匹配它所拥有的所有Context。Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为“ ”的Context去处理);
5.path=“/test”的Context获得请求/index.jsp,在它的mapping table中寻找出对应的Servlet。Context匹配到URL Pattern为*.jsp的Servlet,对应于JspServlet类;
6.构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet()或doPost(),执行业务逻辑、数据存储等;
7.Context把执行完之后的HttpServletResponse对象返回给Host;
8.Host把HttpServletResponse对象返回给Engine;
9.Engine把HttpServletResponse对象返回Connector;
10.Connector把HttpServletResponse对象返回给客户Browser。
Connector内部架构分析
-
Connector用于接受请求并将请求封装成Request和Response,然后交给Container进行处理,Container处理完之后在交给Connector返回给客户端
-
Connector就是使用ProtocolHandler来处理请求的,不同的ProtocolHandler代表不同的连接类型
Container内部架构分析
(1)Engine:引擎,用来管理多个站点,一个Service最多只能有一个Engine;
(2)Host:代表一个站点,也可以叫虚拟主机,通过配置Host就可以添加站点;
(3)Context:代表一个应用程序,对应着平时开发的一套程序,或者一个WEB-INF目录以及下面的web.xml文件;
(4)Wrapper:每一Wrapper封装着一个Servlet;
Context和Host的区别是Context表示一个应用,我们的Tomcat中默认的配置下webapps下的每一个文件夹目录都是一个Context,其中ROOT目录中存放着主应用,其他目录存放着子应用,而整个webapps就是一个Host站点。
Tomcat的执行流程小结
-
首先,使用 startup 命令,Server标签的端口号8005监听到命令后,开启Tomcat服务器的服务
-
客户端发起请求,Tomcat的8080端口收到请求,开始一系列的处理
-
当一个请求发送到Tomcat之后,首先经过Service然后会交给Connector,Connector用于接收请求并将接收的请求封装为Request和Response来具体处理,Request和Response封装完之后再交由Container内的Servlet进行处理,Container处理完请求之后再返回给Connector,最后在由Connector通过Socket将处理的结果返回给客户端,这样整个请求的就处理完了!
-
Connector最底层使用的是Socket来进行连接的,Request和Response是按照HTTP协议来封装的,所以Connector同时需要实现TCP/IP协议和HTTP协议!
-
最后总结一下:
(1)Tomcat中只有一个Server,一个Server可以有多个Service(用于具体提供服务),一个Service可以有多个Connector(因为一个服务可以有多个连 接)和一个Container; (2) Server掌管着整个Tomcat的生死大权; (4)Service 是对外提供服务的; (5)Connector用于接受请求并将请求封装成Request和Response来具体处理; (6)Container用于封装和管理Servlet,以及具体处理request请求;
| Servlet 概述、接口实现
Servlet的基本概述
-
前面提到了,Servlet 是存在于 Tomcat中的Container中的Wrapper中的一个接口。对于程序员而言,无需深入Tomcat的底层实现。我们只需要知道:Javaweb开发,很大程度上就是在操作Tomcat中的Servlet接口:编写Servlet实现类的代码、在Tomcat的网站核心配置文件 web.xml中配置Servlet实现类对象和URL的映射关系等等……
-
狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
-
Servlet的作用:
-
在Servlet规范中,指定【动态资源文件】开发步骤
-
在Servlet规范中,指定Http服务器调用动态资源文件规则
-
在Servlet规范中,指定Http服务器管理动态资源文件实例对象规则
-
-
Tomcat服务器目录下lib文件有一个servlet-api.jar。这个就是Servlet接口的jar包~
-
Servlet规范中,HTTP服务器(Tomcat)能调用的【动态资源文件】必须是一个Servlet接口实现类
实现Servlet接口并通过URL访问:四大步骤
【前期准备】创建一个web Module
Step1.创建一个普通Java Module
Step2.右键模块,添加WEB框架支持。点击确认,就创建好了一个网站
【Step1】编写一个类,实现HttpServlet接口
-
一般是继承Servlet接口已经写好的实现类HttpServlet,而不是直接 implements Servlet接口。目的是简化需要重写的方法数量,减少开发难度
-
若没有导入Servlet类的Jar包,可以Ctrl+Alt+Shift+S 打开 Project Structure - Module - 对应Module。添加 Tomcat目录/lib 下的Servlet.jar
//src/controller/MyServlet.java
public class MyServlet extends HttpServlet {
}
【Step2】根据需要,重写HttpServlet的 doGet( ) 或 doPost( ) 方法
-
IDEA中快捷键:Ctrl+O 选择 doGet 和 doPost
-
通过浏览器URL发送的请求都是GET请求,这里只重写GET即可(POST请求一般由前端method控制,或者重定向控制
【目录结构同Step1】
//src/controller/MyServlet.java
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//super.doGet(req, resp); 如果你是要彻底覆盖父类的doGet方法,不需要父类提供的功能,就可以删除super.doGet(req,resp);这一句
System.out.println("这是Servlet的doGet方法");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//super.doPost(req, resp);
}
}
【Step3】在web.xml配置文件中,把开发好的java类注册到web服务器(Tomcat)
-
web.xml的作用主要是:指定对应Servlet实现类的路径、对象名、以及对象名对应URL的名字
-
Servlet实现类的路径、对象名 写在 <servlet></sevlet> 里面
Servlet实现类的对象名和URL的映射 写在 <servlet-mapping></servlet-mapping> 里面
易错:<url-pattern>/web1</url-pattern> 中的别名,一定要以 / 开头!!!!
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--在Tomcat目录下的【网站核心配置文件 web.xml】,注册Servlet的实现类-->
<servlet>
<servlet-name>MyServletName</servlet-name><!--【Servlet实现类的对象】的名字(动态代理 自动生成)-->
<servlet-class>controller.MyServlet</servlet-class><!--【Servlet实现类】相对于src的路径-->
</servlet>
<!--将刚才注册的Servlet实现类的【对象名】对应网站中【作为url时的别名】-->
<servlet-mapping>
<servlet-name>MyServletName</servlet-name>
<url-pattern>/web1</url-pattern><!--若当URL中有/web1:当Tomcat收到之后,会到web.xml中寻找对应的Servlet实现类对象名,然后动态代理根据其对应的类路径生成对象,执行业务代码-->
</servlet-mapping>
</web-app>
【Step4】把网站部署到web服务器(Tomcat):运行 – 编辑配置 – 部署
部署步骤同 IDEATomcat 静态资源网站访问
然后部署后,进入浏览器访问即可
IDEA一键生成Servlet实现类
-
在一键生成前,需要确保当前Mudule(Ctrl+Alt+Shift+S 打开Project Structure)导入了Servlet包
右键,选择Servlet即可(注意Servlet的实现类所属包一般都是controller下)
-
若没有发现有Servlet选项,则还是建议你老老实实自己创建吧……反正也不麻烦。
-
选项里没有Servlet的解决办法(不推荐使用,会破坏目录结构,仅作参考)参考资料
| Servlet对象的 周期与load-on-startup
Servlet对象的生命周期
-
网站中所有的Servlet接口实现类的实例对象,只能由Http服务器负责创建。开发人员不能手动创建Servlet接口实现类的实例对象
-
在Http服务器运行期间,一个Servlet接口实现类只能被创建出一个实例对象,但是能被多次执行(即被URL访问多次)
-
在Http服务器关闭后,自动将网站中所有的Servlet对象进行销毁
Servlet对象的创建时机 & load-on-startup配置参数
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>MyServletName</servlet-name>
<servlet-class>controller.MyServlet</servlet-class>
<load-on-startup>0</load-on-startup><!--填写一个大于0的整数即可。Tomcat会在启动后自动创建Servlet实现类对象。数字代表创建优先级-->
</servlet>
<servlet-mapping>
<servlet-name>MyServletName</servlet-name>
<url-pattern>/web1</url-pattern>
</servlet-mapping>
</web-app>
-
Servlet对象的创建时机(即初始化的时机)
-
若没有在web.xml给对应的Servlet对象配置 load-on-startup 参数,则容器一般在第一次响应web请求时创建对象,会先检测该servlet是否初始化,如未初始化,则调用servlet的init()先初始化,初始化成功后,再响应请求。
-
若配置了 load-on-startup 参数,servlet将在Tomcat启动startup后立即创建对应实现类对象,但只是调用servlet的init()方法,用以初始化该servlet相关的资源。初始化成功后,该servlet可响应web请求
-
-
load-on-startup参数的作用
-
标记容器是否在启动的时候就加载这个servlet。
-
中间的数值必须是个整数。
-
>=0时,表示容器在启动时就会初始化这个servlet类。数值越小优先级越高,加载的越早
< 0时,表示当调用这个servlet类时才会将其实例化。
-
如果我们在web.xml中设置了多个servlet的时候,可以使用load-on-startup来指定servlet的加载顺序,服务器会根据load-on-startup的大小依次对servlet进行初始化。不过即使我们将load-on-startup设置重复也不会出现异常,服务器会自己决定初始化顺序
-
验证 “Servlet对象只能被创建一次,但是能被多次调用” 和 验证load-on-startup确实能改变Servlet实现类的创建时机
-
init()方法可以理解为 Servlet实现类被创建时候的构造方法
//src/controller/MyServlet.java
public class MyServlet extends HttpServlet {
//可以重写 init 方法,这个init方法代表对象被创建时候调用初始化。
@Override
public void init() throws ServletException {
super.init();
System.out.println("MyServlet对象被创建了");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//...
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--在Tomcat目录下的【网站核心配置文件 web.xml】,注册Servlet的实现类-->
<servlet>
<servlet-name>MyServletName</servlet-name><!--【Servlet实现类的对象】的名字(动态代理 自动生成)-->
<servlet-class>controller.MyServlet</servlet-class><!--【Servlet实现类】相对于src的路径-->
<load-on-startup>0</load-on-startup><!--填写一个大于0的整数即可。Tomcat会在启动后自动创建Servlet实现类对象。数字代表创建优先级-->
</servlet>
<!--将刚才注册的Servlet实现类的【对象名】对应网站中【作为url时的别名】-->
<servlet-mapping>
<servlet-name>MyServletName</servlet-name>
<url-pattern>/web1</url-pattern><!--若当URL中有/web1:当Tomcat收到之后,会到web.xml中寻找对应的Servlet实现类对象名,然后动态代理根据其对应的类路径生成对象,执行业务代码-->
</servlet-mapping>
</web-app>
验证结果:
-
若该Servlet的web.xml配置中配置了 load-on-startup 参数为 >=0 的整数
-
则点击运行Tomcat,发现立即输出了 “MyServlet对象被创建了”
-
在网页URL中输入 /web1,发现输出了 “doGet中的代码执行结果”
-
后续再多次在URL中访问 /web1,发现都可以输出doGet的执行结果,但是“MyServlet对象被创建了”再也没出现过
-
上述现象说明Servlet对象只能被创建一次、但是可以被访问多次,
且还说明了若load-on-startup参数>=0,则Servlet实现类对象会在Tomcat启动时被立即创建
-
-
若该Servlet的web.xml配置中没配置 load-on-startup 参数
-
则点击运行Tomcat,发现什么都没输出(代表Servlet对象还没被初始化,即对象还没被创建)
-
在网页URL中第一次输入 /web1,发现输出了 “MyServlet对象被创建了” 和 “doGet中的代码执行结果”
-
上述现象说明Servlet对象若配置了 load-on-startup 参数,则会在Tomcat启动的时候就立即被创建,否则只会等到第一次用到的时候才创建
-