百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

不知道这些Servlet规范、容器,还敢说自己是Java程序员?

yuyutoo 2024-10-26 16:09 14 浏览 0 评论

Servlet是一种基于Java技术的Web组件,用于生成动态内容,由容器管理。类似于其它Java技术组件,Servlet 是平台无关的Java类组成,并且由Java Web服务器加载执行。

通常由Servlet容器提供运行时环境。Servlet 容器,有时候也称作为Servlet引擎,作为Web服务器或应用服务器的一部分 。通过请求和响应对话,提供Web客户端与Servlets 交互的能力。容器管理Servlets实例以及它们的生命周期。

浏览器发给服务端的是一个HTTP格式的请求,HTTP服务器收到这个请求后,需要调用服务端程序来处理。

那HTTP服务器怎么知道要调用哪个处理器方法。最直接的做法是在HTTP服务器代码里写一大堆if else:如果是A请求就调X类的M1方法,如果是B请求就调Y类的M2方法。

这样设计的问题在于HTTP服务器的代码跟业务逻辑耦合,若新增业务方法还要改HTTP服务器的代码!

面向接口编程是解决耦合问题的银弹,可以定义一个接口,各种业务类都必须实现这个接口,这个接口就是Servlet接口,也把实现了Servlet接口的业务类叫作Servlet。

对特定请求,HTTP服务器如何知道:

  • 由哪个Servlet处理?
  • Servlet该由谁实例化?

显然HTTP服务器并不适合负责这些,否则又和业务类耦合。

Servlet容器

于是,又设计Servlet容器,以加载和管理业务类。HTTP服务器不直接跟业务类打交道,而是把请求交给Servlet容器,Servlet容器会将请求转发到具体Servlet。

若该Servlet还没创建,就加载并实例化这个Servlet,然后调用这个Servlet的接口方法。

因此Servlet接口其实是Servlet容器跟具体业务类之间的接口:

左边表示HTTP服务器直接调用具体业务类,但它们紧耦合。

右边,HTTP服务器不直接调用业务类,而是把请求交给容器,容器通过Servlet接口调用业务类。因此Servlet接口和Servlet容器,实现HTTP服务器与业务类解耦。

Servlet接口和Servlet容器这一整套规范叫作Servlet规范。Tomcat按Servlet规范要求实现了Servlet容器,同时也具有HTTP服务器功能。

若实现新业务,只需实现一个Servlet,并把它注册到Tomcat(Servlet容器),剩下的事情就由Tomcat帮忙处理了。

Servlet接口

Servlet接口定义了下面五个方法:

具体业务类在service方法实现处理逻辑,如下这两个类是对通信协议的封装:

  • ServletRequest:封装请求信息
  • ServletResponse:封装响应信息

HTTP协议中的请求和响应就对应

  • HttpServletRequest:获取所有请求相关的信息,包括请求路径、Cookie、HTTP头、请求参数等。还能创建和获取Session
  • HttpServletResponse:封装HTTP响应

生命周期相关方法:

  • init:Servlet容器在加载Servlet类的时候会调用,可能会在init方法里初始化一些资源。比如Spring MVC中的DispatcherServlet,就是在init方法里创建了自己的Spring容器。
  • destroy:卸载时会调用,可能在destroy方法里释放这些资源

ServletConfig

ServletConfig的作用就是封装Servlet的初始化参数。

可以在web.xml给Servlet配置参数,并在程序通过getServletConfig拿到这些参数。

有接口一般就有抽象类,抽象类用来实现接口和封装通用的逻辑,因此Servlet规范提供了GenericServlet抽象类,可以通过扩展它来实现Servlet。虽然Servlet规范并不在乎通信协议是什么,但是大多数的Servlet都是在HTTP环境中处理的,因此Servet规范还提供了HttpServlet来继承GenericServlet,并且加入了HTTP特性。这样我们通过继承HttpServlet类来实现自己的Servlet,只需要重写两个方法:doGet和doPost。

Servlet容器

工作流程

当客户请求某个资源时

  • HTTP服务器用ServletRequest对象封装客户的请求信息
  • 然后调用Servlet容器的service方法
  • Servlet容器拿到请求后,根据请求的URL和Servlet的映射关系,找到相应的Servlet
  • 如果Servlet还没有被加载,就用反射创建该Servlet
  • 调用Servlet的init方法来完成初始化
  • 调用Servlet的service方法来处理请求
  • 把ServletResponse对象返回给HTTP服务器,HTTP服务器会把响应发送给客户端

Web应用

Servlet容器会实例化和调用Servlet,那Servlet怎么注册到Servlet容器?

根据Servlet规范,Web应用程序有一定目录结构,放置了

  • Servlet的类文件
  • 配置文件
  • 静态资源

Servlet容器通过读取配置文件,就能找到并加载Servlet。Web应用的大致目录结构:

| -  MyWebApp
      | -  WEB-INF/web.xml        -- 配置文件,用来配置Servlet等
      | -  WEB-INF/lib/           -- 存放Web应用所需各种JAR包
      | -  WEB-INF/classes/       -- 存放你的应用类,比如Servlet类
      | -  META-INF/              -- 目录存放工程的一些信息

ServletContext

Servlet规范定义了ServletContext接口对应一个Web应用。

Web应用部署好后,Servlet容器在启动时会加载Web应用,并为每个Web应用创建一个全局的上下文环境ServletContext对象,其为后面的Spring容器提供宿主环境。

可以把ServletContext看成是一个全局对象,一个Web应用可能有多个Servlet,这些Servlet可以通过全局的ServletContext共享数据,这些数据包括Web应用的初始化参数、Web应用目录下的文件资源等。

ServletContext持有所有Servlet实例,所以还能通过它来实现Servlet请求的转发。

Tomcat&Jetty在启动过程中触发容器初始化事件,Spring的ContextLoaderListener会监听到这个事件,它的contextInitialized方法会被调用,在这个方法中,Spring会初始化全局的Spring根容器,这个就是Spring的IoC容器。

IoC容器初始化完毕后,Spring将其存储到ServletContext中,便于以后获取

ServletContext就是用来共享数据的,比如SpringMVC需要从ServletContext拿到全局的Spring容器,把它设置成自己的父容器。

Tomcat&Jetty在启动过程中还会扫描Servlet,一个Web应用中的Servlet可以有多个,以SpringMVC中的DispatcherServlet为例,这个Servlet实际上是一个标准的前端控制器,用以转发、匹配、处理每个Servlet请求。

Servlet一般会延迟加载,当第一个请求达到时,Tomcat&Jetty发现DispatcherServlet还没有被实例化,就调用DispatcherServlet的init方法,DispatcherServlet在初始化的时候会建立自己的容器,叫做SpringMVC 容器,用来持有Spring MVC相关的Bean。同时,Spring MVC还会通过ServletContext拿到Spring根容器,并将Spring根容器设为SpringMVC容器的父容器,请注意,Spring MVC容器可以访问父容器中的Bean,但是父容器不能访问子容器的Bean, 也就是说Spring根容器不能访问SpringMVC容器里的Bean。说得通俗点就是,在Controller里可以访问Service对象,但是在Service里不可以访问Controller对象。

初始化工作

Tomcat/Jetty启动,对于每个WebApp,依次进行初始化工作:

1、对每个WebApp,都有一个WebApp ClassLoader,和一个ServletContext

2、ServletContext启动时,会扫描web.xml配置文件,找到Filter、Listener和Servlet配置

3、如果Listener中配有spring的ContextLoaderListener

3.1、ContextLoaderListener就会收到webapp的各种状态信息。

3.3、在ServletContext初始化时,ContextLoaderListener也就会将Spring IOC容器进行初始化,管理Spring相关的Bean。

3.4、ContextLoaderListener会将Spring IOC容器存放到ServletContext中

4、如果Servlet中配有SpringMVC的DispatcherServlet

4.1、DispatcherServlet初始化时(其一次请求到达)。

4.2、其中,DispatcherServlet会初始化自己的SpringMVC容器,用来管理Spring MVC相关的Bean。

4.3、SpringMVC容器可以通过ServletContext获取Spring容器,并将Spring容器设置为自己的根容器。而子容器可以访问父容器,从而在Controller里可以访问Service对象,但是在Service里不可以访问Controller对象。

4.2、初始化完毕后,DispatcherServlet开始处理MVC中的请求映射关系。

Servlet默认单例模式,Spring的Bean默认也是单例模式,则Spring MVC是如何处理并发请求?

DispatcherServlet中的成员变量都是初始化好后就不会被改变了,所以是线程安全的,那“可见性”怎么保证呢?

由Web容器比如Tomcat保证,Tomcat在调用Servlet的init方法时,用synchronized。

若还没有至少一个已初始化的实例,则加载并初始化该 servlet 的一个实例。 例如,这可用于加载deployment descriptor中标记为在服务器启动时加载的 servlet。

实现说明:类名以org.apache.catalina.开头的 Servlet org.apache.catalina. (所谓的 servlet容器)由加载此类的同一类加载器加载,而非由当前 Web 应用程序的类加载器加载。 这使此类可以访问 Catalina 内部结构,而对于为 Web 应用程序加载的类,这种访问权限是被阻止的

分不清的xxx容器

Servlet容器

用于管理Servlet生命周期。

SpringMVC容器

管理SpringMVC Bean生命周期。

Spring容器

用于管理Spring Bean生命周期。包含许多子容器,其中SpringMVC容器就是其中常用的,DispatcherServlet就是SpringMVC容器中的servlet接口,也是SpringMVC容器的核心类。

Spring容器主要用于整个Web应用程序需要共享的一些组件,比如DAO、数据库的ConnectionFactory等,SpringMVC容器主要用于和该Servlet相关的一些组件,比如Controller、ViewResovler等。

至此就清楚了Spring容器内部的关系。

Spring和SpringMVC分别有自己的IOC容器或上下文,为何分成俩容器?

隔离管理的Bean,各管各的,职责明确。SpringMVC的容器直接管理跟DispatcherServlet相关的Bean,也就是Controller,ViewResolver等,并且SpringMVC容器是在DispacherServlet的init方法里创建的。而Spring容器管理其他的Bean比如Service和DAO。

并且SpringMVC容器是Spring容器的子容器,所谓的父子关系意味着什么呢,就是你通过子容器去拿某个Bean时,子容器先在自己管理的Bean中去找这个Bean,如果找不到再到父容器中找。但是父容器不能到子容器中去找某个Bean。

其实这个套路跟JVM的类加载器设计有点像,不同的类加载器也为了隔离,不过加载顺序是反的,子加载器总是先委托父加载器去加载某个类,加载不到再自己来加载。

并且通过父子关系,使得SpringMVC容器可以从父亲Spring容器那里拿Bean,因为Spring容器管理的是公共的Bean。

当然可以用同一个容器来管理,SpringBoot就是这样做的。

Spring和SpringMVC是通过配置文件来明确指定各自管理的Bean。

Servlet容器跟Spring容器又有什么关系呢?

有人说spring容器是servlet容器的子容器,但是这个servlet容器到底是tomcat实现的容器呢,还是jetty实现的容器呢?所以spring容器与servlet容器他们之间并没有直接的血缘关系,可以说spring容器依赖了servlet容器,spring容器的实现遵循了Servlet 规范。

spring容器只是servlet容器上下文(ServletContext)的一个属性,web容器启动时通过ServletContextListener机制构建出来。SpringBoot中只有一个Spring上下文:

org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext

servlet容器初始化成功后被spring监听,创建spring容器放入servlet容器中,访问到达,初始化dispatcher servlet时创建springmvc容器,通过servletContext拿到spring容器,并将其作为自己的父容器,spring mvc容器会定义controller相关的bean,spring会定义业务逻辑相关的bean。

扩展机制

引入了Servlet规范后,无需关心Socket网络通信、HTTP协议或你的业务类是如何被实例化和调用的,因为这些都被Servlet规范标准化了,我们只需关心怎么实现业务逻辑。

有规范看着很方便,但若规范不能满足你的个性需求,就没法用了,因此设计一个规范或者一个中间件,要充分考虑到可扩展性。

Servlet规范提供了两种扩展机制:Filter和Listener。

Filter

过滤器,该接口允许你对请求和响应做一些统一的定制化处理。Filter是基于过程的,它是过程的一部分,是基于过程行为的。比如:

  • 根据请求频率限制访问
  • 根据地区不同修改响应内容

工作原理

Web应用部署完成后,Servlet容器需要实例化Filter并把Filter链接成一个FilterChain。当请求进来时,获取第一个Filter并调用doFilter方法,doFilter方法负责调用这个FilterChain中的下一个Filter。

Listener

监听器,Listener是基于状态的,任何行为改变同一个状态,触发的事件是一致的。当Web应用在Servlet容器中运行时,Servlet容器内部会不断的发生各种事件,如Web应用的启动和停止、用户请求到达等。 Servlet容器提供了一些默认的监听器来监听这些事件,当事件发生时,Servlet容器会负责调用监听器的方法。当然,你可以定义自己的监听器去监听你感兴趣的事件,将监听器配置在web.xml中。比如Spring就实现了自己的监听器,来监听ServletContext的启动事件,目的是当Servlet容器启动时,创建并初始化全局的Spring容器

FAQ

service方法为什么把request和response都当作输入参数,而不是输入参数只有request,response放到返回值里呢?

方便责任链模式下层层传递。

在SpringBoot项目中,为什么没有web.xml了?

SpringBoot是以嵌入式的方式来启动Tomcat。对于SpringBoot来说,Tomcat只是个JAR包。SpringBoot通过Servlet3.0规范中 @WebServlet 注解或者API直接向Servlet容器添加Servlet,无需web.xml。

作者:JavaEdge.

原文链接:https://blog.csdn.net/qq_33589510/article/details/118763819

相关推荐

从零搭建高可用的 MySQL 主从复制架构(基于 Linux 实战指南)

背景在生产环境中,单点MySQL数据库容易成为性能瓶颈或单点故障源。搭建MySQL主从复制架构,可以实现读写分离、高可用,提升系统的整体稳定性与扩展性。...

国外大神成功让Nexus4吃上安卓6.0:基本可正常使用

IT之家讯10月9日消息谷歌已经于10月6日正式开启了Nexus设备Android6.0Marshmallow系统的OTA升级推送。根据之前报道的消息,老一批的Nexus手机如Nexus4/Ne...

急死!CPU被挖矿了,却找不到哪个进程

CPU起飞了最近有朋友在群里反馈,自己服务器的CPU一直处于高占用状态,但用...

甜甜的安卓5.0却让手机ROOT难度大大增加

IT之家(www.ithome.com):甜甜的安卓5.0却让手机ROOT难度大大增加对设备进行ROOT,毫无疑问,这是安卓最美丽的地方之一,不管是对于消费者来说还是开发者。Root意味着掌握更多的权...

Linux基础知识(linux基础知识点及答案)

系统目录结构/bin:命令和应用程序。/boot:这里存放的是启动Linux时使用的一些核心文件,包括一些连接文件以及镜像文件。/dev:dev是Device(设备)的缩写,该目录...

Linux 内核 6.15 发布:内存、网络、文件系统全面升级!

核心增强:性能与安全双飞升!Linux内核6.15的正式版!虽然因一个临门一脚的Bug晚了几小时,但最终还是带着一堆硬核更新闪亮登场!...

AlmaLinux 9.6 发布,新增功能亮点纷呈!

距离上一版本AlmaLinux9.5发布六个月后,基于5.14内核的AlmaLinux正式宣布其企业级Linux发行版的9.x系列第六个更新——AlmaLinux9.6(Sag...

理解Linux下的SELinux(linux seccomp)

理解Linux下的SELinux长久以来,每当遇到授权问题或者新安装的主机,我的第一反应是通过setenforce0命令禁用SELinux,来减少产生的权限问题,但是这并不是一个良好的习惯。这篇文章...

3个简单实用的网址导航网站(简洁的网站导航)

在我们使用电脑上网的时候经常会访问某些常用的网站,每一次都去通过搜索访问就比较浪费时间,添加在浏览器收藏夹不方便在其他电脑使用。找一个好用的网址导航网站就可以帮我们把所有常用的网址集合在一个页面,方便...

整点不一样的网站制作教程,教你怎么用网站模板制作网站#...

网站制作教程整点不一样的网站。不要再问我网站制作教程了,今天给你整个怎么用网站模板制作网站的教程。·1、登录账号进入后台。·2、选择模板。自助建站平台通常提供各种各样的网站模板,可以根据自己的需求和喜...

5个最好的外贸独立站模板,让你的网站更加专业

作为外贸行业从业者,一个专业且具有吸引力的网站是必不可少的。然而,建立一个专业的网站需要耗费大量的时间和精力,尤其是在设计和开发方面。为了帮助您缩短网站建设的时间和成本,以下是5个最好的外贸独立站模板...

网站建设模板 **网站建设模板:全面指南与创意构思*

网站建设模板**网站建设模板:全面指南与创意构思**随着互联网技术的迅猛发展,网站已成为企业、机构和个人展示自身形象、传递信息、实现交流的重要平台。本文将详细介绍网站建设的基本模板,并提供创意...

原地封神!一个只用套模板即可制作电子相册的网站

对于忙碌的年轻人来说,一键操作的模板意味着无需复杂的操作步骤,就能轻松制作出精美的电子相册。但是一个好的工具也是事关重要,最近发现了一款非常适合年轻人的模板---FLBOOK在线制作电子杂志平台,只需...

跨屏建站网kpfree免费网站模板2023.1.14发布更新

跨屏建站网kpfree免费网站模板2023.1.14发布更新,摒弃了之前的卡片式设计,采用了移动优先的设计原则,简化了页面设计风格,优化了代码,优化了图片质量,确保网页打开速度。砍掉了一些花哨而无用的...

响应式大型电子企业集团类网站模板源码-青柠资源网qnziyw.cn

模板信息:模板编号:10964模板编码:UTF8模板颜色:红色模板分类:科技、电子、数码设备适合行业:电子设备类企业模板介绍:本模板自带eyoucms内核,无需再下载eyou系统,原创设计、手工书写D...

取消回复欢迎 发表评论: