Servlet介绍的以及它的生命周期

本文深入解析Servlet的工作原理,探讨其在B/S架构中的角色,展示了如何通过Servlet简化动态网页开发,并剖析了Servlet的生命周期和请求响应过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 一、概述:

        1、当我们想要访问一个网站时,只需要在浏览器地址栏里输入网址,然后点击搜索或者链接即可,比如www.baidu.com,然后回车浏览器就可以跳转到百度首页了,那么这个过程底层的步骤是怎么实现的呢?这就涉及到http的请求与响应了:

       2、我们访问网站时,大部分场景下都是基于Browser/Server模式(浏览器/服务器模式),简称BS架构,它的特点是,客户端只需要浏览器,应用程序的逻辑和数据都存储在服务器端。浏览器只需要请求服务器,获取网页页面,并把网页页面展示给用户即可,此传输过程遵循Http协议。对于浏览器来说:1.与服务器建立TCP连接; 2 发送HTTP请求; 3 收取HTTP响应,然后把网页在浏览器中显示出来。对于服务器:读取解析请求头,响应回网页(一般是HTML网页),网页中如果嵌入了JavaScript、CSS、图片、视频等其他资源,浏览器会根据资源的URL再次向服务器请求对应的资源,解析之后给用户显示在页面。

二、什么是Servlet?

        1、从上文我们可以得知B/S模式下的每一次动态网页交互其实是比较麻烦,需要服务器解析 HTTP 请求的报头,分析用户的请求参数,加载数据库组件……这些基础工作需要耗费大量的时间,如果我们只需要输出一个简单的HTML页面,就不得不编写上千行底层代码,那就根本无法做到高效而可靠地开发,这些种种原因导致使用原生 Java 开发服务器应用是一件不容易的事情。正是基于这种原因,Java 官方后来推出了 Servlet 技术,它对开发动态网站需要使用的原生 Java API 进行了封装,形成了一套新的 API,称为 Servlet API。

        2、Servlet也称服务连接器,是用Java编写的服务器端程序,主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口:

//Java中Servlet接口源码
public interface Servlet {
 
    public void init(ServletConfig config) throws ServletException;

    public ServletConfig getServletConfig();
 
    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;
   
    public String getServletInfo();
  
    public void destroy();
}

        而我们一般所说的Servlet是指任何实现了这个Servlet接口的类,这个类总是继承自HttpServlet(间接实现了Servlet接口的抽象类),然后覆写doGet()或doPost()方法。被用来扩展服务器的性能,服务器上驻留着可以通过“请求-响应”编程模型来访问的应用程序。虽然 Servlet 可以对任何类型的请求产生响应,但通常只用来扩展 Web 服务器的应用程序。

        3、Servlet动态生成网页的基本过程为:

  1. 客户端发送请求至服务器;
  2. 服务器将请求信息发送至 Servlet;
  3. Servlet 生成响应内容并将其传给服务器。响应内容动态生成,通常取决于客户端的请求;
  4. 服务器将响应返回给客户端。
@WebServlet("/hello.do")
public class HttpServlteTest extends HttpServlet {

	private Set set = new LinkedHashSet<String>();

	// 重写doGet方法:处理get方式请求
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.setContentType("text/html;charset=utf-8");
		System.out.println("哎哟,被get到了哟!");

		int port = req.getServerPort();
		System.out.println(port);

		PrintWriter writer = resp.getWriter();
		String name = req.getParameter("name");
		System.out.println("本次报名:" + name);		

		if (set.add(name)) {
			writer.write(name + ",报名成功");
		} else {
			writer.write(name + ",报名失败,不可重复报名");
		}
		if (name.equals("蔡徐坤")) {
			writer.write(("你干嘛~哎哟"));
		}
		writer.write(set.toString());
		writer.close();
	}
}

运行效果:

三、Servlet的本质,它是到底帮我们做了什么?

        1、上述代码中我们发现在使用Servlet时会发现我们并不需要自己去编写代码解析请求,而只需要处理业务逻辑功能,这是因为我们覆写的doGet()或doPost()方法传入了HttpServletRequest和HttpServletResponse两个对象,分别代表HTTP请求和响应。这两个对象已经封装好了请求和响应。以发送响应为例,我们只需要设置正确的响应类型,然后获取PrintWriter,写入响应即可。

        2、那么Servlet是怎么处理浏览器请求的呢,很显然在我们上面写的Servlet类中并不能体现出来,那么它是依靠什么来实现的呢?答案是Servlet容器,严格来说Servlet API是一套规范,在Servlet类里中根据请求你可以编写代码你想要响应什么,具体的响应过程其实是实现了Servlet API的web服务器来帮你完成的。目前使用最广泛的是Tomcat:由Apache开发的开源免费服务器。我们也俗称这样的服务器为Servlet容器,因为它里面"存放着"Servlet对象,管理我们的Servlet类

        3、所以说啊,我们在写一个Servlet程序的时候肯定是把servlet部署到一个容器中的,容器真正会管理我们的Servlet对象,我们也都知道一个web服务器程序肯定会包括三个步骤:接受请求;处理请求;响应请求,其中接受请求和响应请求在一些方面是其实是有共性的,但是处理请求是看具体业务功能的,得嘞,这部分我们抽出来做成Servlet,在Servlet的类的方法里面写我们的逻辑代码。诶?那好像我们在程序里也没写过main()方法啊,一路走来,我们面向接口编程,现在面向框架编程,就比如先前的JDBC我们连接数据库我们只需要用getConnection()给里面传入数据库连接参数然后得到一个数据库连接对象返回给Connection接口就可以用了,但是底层的校验连接是我们自己实现的吗?显然这不是一个合理的编程思想,于是各大厂商直接附带给我们相应的驱动比如Driver类。

        4、其实Tomcat也一样,在Servlet服务器程序中,我们观察自己写的Servlet类,既不需要我写TCP连接数据库,也不需要我解析HTTP请求,更不需要我把结果转成HTTP响应,会发现其实最主要的的在于覆写的doGet()或doPost()方法传入的HttpServletRequest和HttpServletResponse两个形参,这两个形参就是Tomcat事先封装好的对象,req对象和resp对象已经帮我们把这一系列事情搞定了。就像我们从来不会在servlet中写什么监听8080端口的代码,servlet不会直接和客户端打交道,归根到底Tomcat才是与客户端直接打交道的家伙,它监听端口,拿到请求后,根据url等信息,确定要将请求交给哪个servlet去处理,然后调用那个servlet的service方法,service方法返回一个response对象,Tomcat再把这个response返回给客户端。 

        5、类似Tomcat这样的服务器其实也是Java编写的,启动Tomcat服务器实际上是启动Java虚拟机,执行Tomcat的main()方法,然后由Tomcat负责加载我们的*.war文件(你的Servlet项目),并创建一个HelloServlet实例,最后以多线程的模式来处理HTTP请求。如果Tomcat服务器收到的请求路径是/项目名称/hello.do,就转发到Servlet并传入HttpServletRequest和HttpServletResponse两个对象。

四、Servlet的生命周期

        1、我们无法在代码中直接通过new创建Servlet实例,必须由Servlet容器自动创建Servlet实例,Servlet容器只会给每个Servlet类创建唯一实例,Servlet实例创建和使用的过程,被称为Servlet的生命周期。整个生命周期包括:实例化、初始化、服务、销毁。

        2、从上文我们知道Servlet接口有5个方法,其中init、service、destroy是生命周期方法。init和destroy各自只执行一次,即servlet创建和销毁时。而service会在每次有新请求到来时被调用。也就是说,我们主要的业务代码需要写在service中。

        3、具体过程:实例化:客户端请求到Servlet路径并调用构造方法创建Servlet实例。初始化:通过该Servlet的实例,调用init()方法初始化该Servlet 。服务:通过该Servlet的实例,调用service()方法,如果子类没有重写该方法,则调用HttpServlet父类的service()方法,在父类的该方法中进行请求方式的判断,如果是GET请求,则调用doGet()方法;如果是POST请求,则调用doPost()方法;如果子类没有重写doGet()方法或者其他doxxx()则会调用父类对应的方法报405之类的4开头的错误状态码。销毁:服务器关闭或重启时,会销毁所有的Servlet实例,会调用Servlet实例的destroy()方法。

 

5.Req/Resp:

        Tomcat帮我们将一个HTTP请求封装进了HttpServletRequest,即参数对象req,通过此对象可以拿到HTTP请求的几乎全部信息,常用的方法有:

● getMethod():返回请求方法,例如,"GET","POST";

● getRequestURI():返回请求路径,但不包括请求参数,例如,"/hello";

● getQueryString():返回请求参数,例如,"name=Bob&a=1&b=2";

●getxxx()......

        至于Response,Tomcat传给Servlet时,它还是空的对象。Servlet逻辑处理后得到结果,最终通过response.write()方法,将结果写入response内部的缓冲区。Tomcat会在servlet处理结束后,拿到response,遍历里面的信息,组装成HTTP响应发给客户端。写入完毕后必须调用flush()方法,因为大部分Web服务器都基于HTTP/1.1协议,会复用TCP连接。如果没有调用flush(),将导致缓冲区的内容无法及时发送到客户端。

        由于HTTP响应必须先发送Header,再发送Body,所以,操作HttpServletResponse对象时,必须先调用设置Header的方法,最后调用发送Body的方法。 常用的设置Header的方法有:

        ● setStatus(sc):设置响应代码,默认是200;

        ● setContentType(type):设置Body的类型,例如,"text/html";

        ● setCharacterEncoding(charset):设置字符编码,例如,"UTF-8";

        ● setHeader(name, value):设置一个Header的值;

总结:Servlet就是人们制定java应用中使用web服务时的各种规范,统一接口,其他内部实现由厂商自己实现,比如tomcat jetty GlassFish等等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值