不知道这些Servlet规范、容器,还敢说自己是Java程序员?
yuyutoo 2024-10-26 16:09 10 浏览 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
相关推荐
- 深度解读Spring框架的核心原理
-
深度解读Spring框架的核心原理在Java开发的世界里,提到Spring框架,就像提起一位久经沙场的老将,它几乎成了企业级应用开发的代名词。那么,这个被无数开发者膜拜的框架究竟有何独特之处?今天,我...
- 「Spring认证」Spring 框架概述
-
Spring是最流行的企业Java应用程序开发框架。全球数以百万计的开发人员使用SpringFramework来创建高性能、易于测试和可重用的代码。Spring框架是一个开源的Java...
- 学习Spring框架 这一篇就够了
-
1.spring概述1.1Spring是什么(理解)...
- Spring框架双核解析:IOC与AOP的本质与实战
-
#Spring核心#IOC容器#AOP编程#Java框架设计...
- Spring Boot与传统Spring框架的对比:探索Java开发的新境界
-
SpringBoot与传统Spring框架的对比:探索Java开发的新境界在Java生态系统中,Spring框架无疑是一个里程碑式的存在。从最初的简单依赖注入容器,到如今覆盖企业级开发方方面面的庞大...
- Spring MVC框架源码深度剖析:从入门到精通
-
SpringMVC框架源码深度剖析:从入门到精通SpringMVC框架简介SpringMVC作为Spring框架的一部分,为构建Web应用程序提供了强大且灵活的支持。它遵循MVC(Model-V...
- Spring框架入门
-
一.spring是什么?Spring是分层...
- 程序员必知必会技能之Spring框架基础——面向切面编程!
-
面向切面编程AOP(AspectOrientedProgramming)与OOP(ObjectOrientedProgramming,面向对象编程)相辅相成。AOP提供了与OOP不同的抽象软件结...
- Spring Security安全框架深度解读:为你的应用穿上“钢铁铠甲”
-
SpringSecurity安全框架深度解读:为你的应用穿上“钢铁铠甲”在现代网络世界里,保护我们的应用程序免受各种威胁攻击至关重要。而在这个过程中,SpringSecurity框架无疑是我们最可...
- Spring框架的设计哲学与实现:打造轻量级的企业级Java应用
-
Spring框架的设计哲学与实现:打造轻量级的企业级Java应用Spring框架自2003年诞生以来,已成为企业级Java应用开发的代名词。它不仅仅是一个框架,更是一种设计理念和哲学的体现。本文将带你...
- Spring框架深度解析:从核心原理到底层实现的全方位避坑指南
-
一、Spring框架核心概念解析1.控制反转(IoC)与依赖注入(DI)Spring的核心思想是通过IoC容器管理对象的生命周期和依赖关系。传统开发中,对象通过new主动创建依赖对象,导致高耦合;而S...
- Java框架 —— Spring简介
-
简介一般来说,Spring指的是SpringFramework,它提供了很多功能,例如:控制反转(IOC)、依赖注入...
- Spring 框架概述,模块划分
-
Spring框架以控制反转(InversionofControl,IoC)和面向切面编程(Aspect-OrientedProgramming,AOP)为核心,旨在简化企业级应用开发,使开发者...
- spring框架怎么实现依赖注入?
-
依赖注入的作用就是在使用Spring框架创建对象时,动态的将其所依赖的对象注入到Bean组件中,其实现方式通常有两种,一种是属性setter方法注入,另一种是构造方法注入。具体介绍如下:●属性set...
- Spring框架详解
-
Spring是一种开放源码框架,旨在解决企业应用程序开发的复杂性。一个主要优点就是它的分层体系结构,层次结构让你可以选择要用的组件,同时也为J2EE应用程序开发提供了集成框架。 Spring特征...
你 发表评论:
欢迎- 一周热门
-
-
前端面试:iframe 的优缺点? iframe有那些缺点
-
带斜线的表头制作好了,如何填充内容?这几种方法你更喜欢哪个?
-
漫学笔记之PHP.ini常用的配置信息
-
推荐7个模板代码和其他游戏源码下载的网址
-
其实模版网站在开发工作中很重要,推荐几个参考站给大家
-
[干货] JAVA - JVM - 2 内存两分 [干货]+java+-+jvm+-+2+内存两分吗
-
正在学习使用python搭建自动化测试框架?这个系统包你可能会用到
-
织梦(Dedecms)建站教程 织梦建站详细步骤
-
【开源分享】2024PHP在线客服系统源码(搭建教程+终身使用)
-
2024PHP在线客服系统源码+完全开源 带详细搭建教程
-
- 最近发表
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)