JAVA WEB中Servlet和Servlet容器的区别

Servlet

很多同学可能跟我一样始终没有搞清楚到底什么是 Servlet,什么是 Servlet 容器。网上看了很多帖子,或许人家说的很清楚,但是自己的那个弯弯就是拐不过来。

想了很久说一下自己的理解。

Java web 开发中为啥要有 Servlet 呢?是否可以不要。

web开发的本质就一句话:客户端和服务器交换数据。于是你使用 Java 的 Socket 套接字进行编程,去处理客户端来的 tcp 请求,经过编解码处理读取请求体,获取请求行,然后找到请求行对应的处理逻辑步入服务器的处理中,处理完毕把对应的结果返回给当前的 Socket 链接,响应完毕,关闭 Socket。

以上过程,你有没有发现其实是两个部分:

建立连接,传输数据,关闭连接,你肯定知道这些步骤不是你所开发的web服务去处理的,而是tomcat容器帮你做了这些事情。

拿到请求行之后去找对应的 url 路由,这一部分是谁做的呢?在如今 SpringBoot 横行的时代,去配置化已经成为趋势,编程越来越简单导致的后果就是越来越难以理解事物最开始的样子。还记得 SpringMVC工程中的 web.xml文件吗?是否还记得在web.xml中有这么一段配置呢:

<servlet>
	<servlet-name>SpringMVC</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet
	</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath*:/spring/SpringMVC-servlet.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>SpringMVC</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>

Spring 的核心就是一个 Servlet,它拦截了所有的请求,将请求交给 DispatcherServlet 去处理。
我们再来问一遍,Servlet 到底是什么,它就是一段处理 web 请求的逻辑,并不是很高深的东西。

再来看 Java 中的 Servlet,它只是一个接口:

package javax.servlet;

import java.io.IOException;

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 接口规定请求从容器到达 web 服务端的规范,最重要的三个步骤是:

  1. init():初始化请求的时候要做什么;
  2. service():拿到请求的时候要做什么;
  3. destory():处理完请求销毁的时候要做什么。

所有实现 Servlet 的实现方都是在这个规范的基础上进行开发。那么 Servlet 中的数据是从哪里来的呢?答案就是 Servlet 容器。容器才是真正与客户端打交道的那一方。Servlet容器只有一个,而 Servlet 可以有多个。常见的Servlet容器Tomcat,它监听了客户端的请求端口,根据请求行信息确定将请求交给哪个Servlet 处理,找到处理的Servlet之后,调用该Servlet的 service() 方法,处理完毕将对应的处理结果包装成ServletResponse 对象返回给客户端。

Servlet 容器

上面说过,Servlet 只是一个处理请求的应用程序,光有Servlet是无法运行起来的,需要有一个 main 方法去调用你的这段 Servlet 程序才行。所以这里出现了Servlet 容器的概念。Servlet容器的主要作用是:

  1. 建立连接;
  2. 调用Servlet处理请求;
  3. 响应请求给客户端;
  4. 释放连接;

这上面的四步,如果是你来设计的话是否可以用一个模板方法搞定,1,3,4都是固定的步骤,不会因为请求不同而有很大的变化。2却会因为对应的请求不同需要业务逻辑自己去实现不同的处理。所以这里抽象出来了 Servlet,Servlet想怎么玩就怎么玩,这是你自己的事情。容器帮你做的是你不想做的脏活累活。

另外,既然叫做容器肯定是能装多个Servlet,并且可以管理Servlet的声明周期。这些功能应该是容器必备的。

上面提到了 web.xml 中的 DispatcherServlet,它是 Spring 中定义的一个 Servlet,实现了 Servlet 接口,本质也是一个 Servlet。只是它是 HttpServlet 的继承者,主要处理 http 请求。所以 Spring 程序本质是就是一个 Servlet。SpringMVC 帮你做了本该你去实现的逻辑,你看不到并不代表它不是。

好啦,以上通俗的语言解释了什么是 Servlet,什么是 Servlet 容器,以及 Servlet 和 Servlet 容器之间的关系。

Tomcat

Tomcat是啥呢?本质上是一个 Servlet 容器,实现了对 Java Servlet 规范的支持。同时 Tomcat 也提供了处理HTTP请求的能力,所以也可以作为一个Web服务器。了解到Tomcat有 Web服务器和 Servlet容器的功能,那么 Tomcat总体是如何设计的呢?我们来看一张简图:

Java web 应用如果部署到 Tomcat 中,一个Tomcat就表示一个服务。一个 Server 服务器可以包含多个 Service 服务,Tomcat 默认的 Service 服务是 Catalina,而一个 Service 服务可以包含多个连接器,因为 Tomcat 支持多种网络协议,包括 HTTP/1.1、HTTP/2、AJP 等等,一个 Service 服务还会包括一个容器,容器外部会有一层 Engine 引擎所包裹,负责与处理连接器的请求与响应,连接器与容器之间通过 ServletRequest 和 ServletResponse 对象进行交流。

Tomcat容器的设计提现在一个核心文件中:server.xml。这个文件充分展示了Tomcat的高度抽象设计:

<Server port="8005" shutdown="SHUTDOWN">
 <Service name="Catalina">
  <Connector port="8080" protocol="HTTP/1.1"
     connectionTimeout="20000"
     redirectPort="8443"/>
  	<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>
				<Engine name="Catalina" defaultHost="localhost">
   	<Host name="localhost" appBase="webapps"
     	unpackWARs="true" autoDeploy="true">

   </Host>
  </Engine>
 </Service>
</Server>

其中:

1. Server 组件是管理 tomcat 实例的组件,可以监听一个端口,从此端口上可以远程向该实例发送 shutdown 关闭命令。

2. Service 组件是一个逻辑组件,用于绑定 connector 和 container,有了 service 表示可以向外提供服务,就像是一般的 daemon 类服务的 service。可以认为一个 service 就启动一个JVM,更严格地说,一个 engine 组件才对应一个 JVM (定义负载均衡时,jvmRoute 就定义在 Engine 组件上用来标识这个 JVM ),只不过 connector 也工作在 JVM 中。

小故事:

是否关注到 Service name = Catalina,实际上 Tomcat 的前身就是 Catalina,这是一个岛的名字,而

Catalina 只是一个 Servlet 容器,为Servlet和 JavaServer Pages(JSP)实现了Sun Microsystems的规范。

Tomcat 的作者 詹姆斯·邓肯·戴维森,Sun Microsystems 的软件架构师在后来 Sun Microsystems 向 Apache Software Foundation 捐赠该项目中发挥了重要作用。当时他认为许多开源项目都有与 O'Reilly 相关的书籍,封面上有动物,所以他想以动物命名。后来这位老哥想到了猫🐈。他认为这只动物代表着某种可以自己生存的东西,当2003年 O'Reilly 发行带有雪豹的 Tomcat 书籍时,他希望看到动物封面的愿望终于实现了。

3. Connector 组件是监听组件,它有四个作用:

  1. 开启监听套接字,监听外界请求,并和客户端建立 TCP 连接;
  2. 使用 protocolHandler 解析请求中的协议和端口等信息,如 http 协议、AJP 协议;
  3. 根据解析到的信息,使用 processer 将分析后的请求转发给绑定的 Engine;
  4. 接收响应数据并返回给客户端。

上面的 server.xml 配置我们能看到有两个 Connector。

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/>

这个 Connector 表示通过 8080 端口使用 HTTP/1.1版本的协议来访问 Tomcat。

我们知道 80 端口是为 HTTP(HyperText Transport Protocol) 即 超文本传输协议 开放的,主要用于万维网传输信息的协议。而我们一般在 Tomcat 中监听的是一个非 80 端口。那为啥不直接在 Tomcat 中写上 80 端口,即所有 HTTP 请求都可以收到。这是因为在生产环境中,一般不会直接暴露原始服务给外网,一方面是安全性,另一方面是 负载均衡处理 和 静态资源处理。所以会在原始服务上加一层代理,代理来监听 80 端口,再将服务暴露端口的请求转发给对应服务。

第二个 Connector:

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>

这个 Connector 监听 8009 端口的 AJP 协议连接。AJP 协议负责和其他的 HTTP 服务器(如 Apache )建立连接;在把 Tomcat 与其他 HTTP 服务器集成时,就需要用到这个连接器。之所以使用 Tomcat 和其他服务器集成,是因为 Tomcat 可以用作 Servlet/JSP 容器,但是对静态资源的处理速度较慢,不如 Apache 和 IIS 等 HTTP 服务器。因此常常将 Tomcat 与 Apache 等集成,前者作 Servlet 容器,后者处理静态资源,而 AJP 协议便负责 Tomcat 和 Apache 的连接。

Container 表示一类组件,在配置文件(server.xml)中没有体现出来。它包含4个容器类组件:Engine容器、Host容器、Context容器 和 wrapper容器。

Engine 容器用于从 Connector 组件处接收已建立的 TCP 连接,还用于接收客户端发送的 HTTP 请求并分析请求,然后按照分析的结果将相关参数传递给匹配出的虚拟主机。Engine 还用于指定默认的虚拟主机。

Host 容器定义虚拟主机,对应了服务器中一个网络名实体(如”www.baidu.com”,或IP地址”23.0.32.1”)。为了使用户可以通过域名连接 Tomcat 服务器,这个域名应该在域名服务器已经注册过。

比如上例中的配置:

<Host name="localhost" appBase="webapps"
     	unpackWARs="true" autoDeploy="true">

name=localhost 表示当前对应的请求是本机,这是因为已经配置了Nginx代理的原因,如果没有配置代理,那么这里就必须是真实的IP 或者域名。注意后面的 appBase,appBase表示当前 web资源所在的目录。

Context 容器主要是根据 path 和 docBase 获取一些信息,将结果交给其内的 wrapper 组件进行处理(它提供wrapper运行的环境,所以它叫上下文context)。一般来说,都采用默认的标准 wrapper 类,因此在 Context 容器中几乎不会出现 wrapper 组件。

wrapper 容器对应 Servlet 的处理过程。它开启 Servlet 的生命周期,根据 Context 给出的信息以及解析 web.xml 中的映射关系,负责装载相关的类,初始化 servlet 对象 init()、执行 servlet 代码 service() 以及服务结束时 servlet 对象的销毁 destory()。

根据上面描述的 tomcat 组件体系结构,处理请求的大致过程其实很容易推导出来:

Client(request)-->Connector-->Engine-->Host-->Context-->Wrapper(response data)-->Connector(response header)-->Client

可以看到宏观上 Tomcat 设计的真是非常精妙,层叠式的容器设计呈现出一种美感。Connector 和 Container 两大组件涵盖主要功能,这种复合组件化的设计思想我们是否可以应用在业务系统中呢。右面有空继续分析 Tomcat 中各个模块的设计。

以上就是JAVA WEB中Servlet和Servlet容器的区别的详细内容,更多关于JAVA WEB Servlet和Servlet容器的资料请关注我们其它相关文章!

(0)

相关推荐

  • JavaWeb项目Servlet无法访问问题解决

    这篇文章主要介绍了JavaWeb项目Servlet无法访问问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.创建Servlet 2.在jsp中用ajax调用 $.post("<%=request.getContextPath()%>/AjaxValidationServlet",{"userName":userName},function(message){ alert(message); }

  • javaweb servlet生成简单验证码

    本文实例为大家分享了javaweb servlet生成验证码的具体代码,供大家参考,具体内容如下 package com.serv; import java.awt.Color; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; import javax.imageio.ImageIO; import javax.s

  • JavaWeb组件Servlet使用实例解析

    在JavaWeb中有三大组件,分别是Servlet.Filter和Listener.其中Servlet的作用是处理请求,服务器会把接收到的请求交给Servlet来处理,即接收请求数据.处理请求和完成响应. 1. 实现Servlet的方式 主要有三种实现方式:1)实现javax.servlet.Servlet接口:2)继承javax.servlet.GenericServlet类:3)继承javax.servlet.http.HttpServlet类:其中最常用的继承HttpServlet类来实现

  • java web用servlet监听器实现显示在线人数

    本文实例为大家分享了java web用servlet监听器实现显示在线人数,供大家参考,具体内容如下 1.创建一个监听器 package com.listener; import javax.servlet.ServletContext; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; //使用监听器实现显示在线人数 public

  • 基于Java web服务器简单实现一个Servlet容器

    上篇写了一个简单的Java web服务器实现,只能处理一些静态资源的请求,本篇文章实现的Servlet容器基于前面的服务器做了个小改造,增加了Servlet请求的处理.  程序执行步骤  1.创建一个ServerSocket对象:  2.调用ServerSocket对象的accept方法,等待连接,连接成功会返回一个Socket对象,否则一直阻塞等待:  3.从Socket对象中获取InputStream和OutputStream字节流,这两个流分别对应request请求和response响应:

  • JAVA WEB中Servlet和Servlet容器的区别

    Servlet 很多同学可能跟我一样始终没有搞清楚到底什么是 Servlet,什么是 Servlet 容器.网上看了很多帖子,或许人家说的很清楚,但是自己的那个弯弯就是拐不过来. 想了很久说一下自己的理解. Java web 开发中为啥要有 Servlet 呢?是否可以不要. web开发的本质就一句话:客户端和服务器交换数据.于是你使用 Java 的 Socket 套接字进行编程,去处理客户端来的 tcp 请求,经过编解码处理读取请求体,获取请求行,然后找到请求行对应的处理逻辑步入服务器的处理中

  • Java Web中解决路径(绝对路径与相对路径)问题

    Java Web中解决路径问题: Java中使用的路径,分为两种:绝对路径和相对路径.归根结底,Java本质上只能使用绝对路径来寻找资源.所有的相对路径寻找资源的方法,都不过是一些便利方法.不过是API在底层帮助我们构建了绝对路径,从而找到资源的! 在开发Web方面的应用时, 经常需要获取 服务器中当前WebRoot的物理路径. 如果是Servlet , Action , Controller, 或则Filter , Listener , 拦截器等相关类时, 我们只需要获得ServletCont

  • java web中图片验证码功能的简单实现方法

    用户在注册网站信息的时候基本上都要数据验证码验证.那么图片验证码功能该如何实现呢? 大概步骤是: 1.在内存中创建缓存图片 2.设置背景色 3.画边框 4.写字母 5.绘制干扰信息 6.图片输出 废话不多说,直接上代码 package com.lsgjzhuwei.servlet.response; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.image.Buffer

  • JSP学习之Java Web中的安全控制实例详解

    本文实例讲述了JSP学习之Java Web中的安全控制.分享给大家供大家参考.具体如下: 一.目标: ① 掌握登录之后的一般处理过程: ② 能够为每个页面添加安全控制: ③ 能够共享验证代码: ④ 使用过滤器对权限进行验证: ⑤ 能够对文件的局部内容进行验证: ⑥ 掌握安全验证码的基本实现方式: ⑦ 通过异常处理增强安全性. 二.主要内容: ① 通过修改前面的登录功能,分别对管理员和普通用户的登录进行处理: ② 为管理员才能访问的页面添加控制: ③ 共享各个页面中的控制代码,使用专门的文件,然后

  • 浅谈java web中常用对象对应的实例化接口

    1. request对象 是javax.servlet.HttpServletRequest接口的实例化 2. response对象 是javax.servlet.HttpServletResponse接口的实例化 3. session 对象 是javax.servlet.HttpSession接口的实例化 4. application对象 是javax.servlet.ServletContext接口的实例化 以上是常用的对象 5. pageContext对象 是javax.servlet.j

  • java web中使用cookie记住用户的账号和密码

    毕业设计中需要用到记住账号密码的功能,网上搜到了一个解决方案,自己稍加改造就是下面的方法. 首先是登录的页面,当用户勾选记住密码,传递给controller(我用的SSM框架),后台设置cookie的值,然后下次登录的时候就不用再次输入账号和密码了. login.jsp的代码: <%@page import="org.apache.commons.lang.StringUtils"%> <%@ page language="java" conten

  • Java Web中常用的分页组件(Java端实现)

     前言 好久没写Web程序了,这一段时间看了看原来师弟们做的一些程序,感觉还是有很多不足,一个比较典型的例子就是分页查询的实现,正好借着这个机会简单记录一下. 分析 使用场景 "分页"在Web程序里非常常见,比如我们在页面上经常要展示一些列表信息,通常情况下,如果数据过多,我们在一屏上难以罗列出所有的记录,而且很多时候我们可能只是看看比较Top的一些记录,因此,在这种情况下使用"分页"查询只展示部分数据是比较合适的. 实现原理 从数据库角度上来说,分页查询实现的难度

  • java web中对json的使用详解

    一.在Java Web的开发过程中,如果希望调用Java对象转化成JSON对象等操作.则需要引入以下jar包,不然运行时则报错. 1.commons-beanutils.jar 2.commons-collections.jar 3.commons-lang.jar 4.commons-logging-1.1.jar 5.ezmorph-1.0.3.jar 6.json-lib-2.0-jdk15.jar 7.有人说还需要 commons-httpclient.jar 引入成功之后,使用JSON

  • 详谈Java泛型中T和问号(通配符)的区别

    类型本来有:简单类型和复杂类型,引入泛型后把复杂类型分的更细了. 概述 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口.泛型方法. Java语言引入泛型的好处是安全简单. 在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的"任意化","任意化"带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对

  • Java web中 war exploded 的解决方案

    Java web war exploded 解决 当出现这个问题时先不要慌 检查这两个地方的 " / "加上没 改成 或web.xml 中的配置地址时是不是忘了加" / " 导入Java web项目 生成war exploded 遇到的问题: 导入wab项目时,tomcat–>Deployment设置,加入不了新导入的项目的war exploded 解决方案: 1.导入项目:Priject Structure->module---->import

随机推荐