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

JAVA网络编程基本功之Servlet与Servlet容器

yuyutoo 2024-12-04 16:50 1 浏览 0 评论

Servlet与Servlet容器关系


Servlet


比较这两个的区别, 就得先搞清楚Servlet 的含义, Servlet (/?s?rvlit/ ) 翻译成中文就是小型应用程序或者小服务程序, 与之相类似的是Server (/?s??rv?r/), 翻译过来是服务器的意思, 可见这二者承担类似的功能,但是Servlet更轻量,


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


上述过程中, 建立连接、传输数据、关闭连接等过程是tomcat容器帮你做了这些事情, 而拿到请求行之后去找对应的 url 路由,这一部分是谁做的呢?是Servlet ! 简单来说Servlet就是一段处理 web 请求的逻辑。


具体来说Servlet具有以下几个特点:


  1. Servlet是用Java编写的Server端程序,它与协议和平台无关。
  2. Servlet运行于Java-enabled Web Server中。
  3. Java Servlet可以动态地扩展Server的能力,并采用请求-响应模式提供Web服务。
  4. 最早支持Servlet技术的是JavaSoft的Java Web Server。
  5. 此后,一些其它的基于Java的Web Server开始支持标准的Servlet API。
  6. Servlet的主要功能在于交互式地浏览和修改数据,生成动态Web内容。


上面六点中,最需要被记住的是Servlet可以动态地扩展Server的能力,并采用请求-响应模式提供Web服务


JDK中的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 是一个接口, 规定了请求从容器到达 web 服务端的规范,详细内容在后面的Servlet生命周期中详细梳理,这儿简单概括三个重要步骤是:


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


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


Servlet容器


现在讲讲Servlet容器, 前面说过看Servlet只是一个接口或者说是规范, 那么就势必有具体实现, 而Servlet具体实现或者说包装器是Wrapper, 直接管理Wrapper的容器就是Context, 一个 Context 对应一个 Web 工程, 也就是说Context 容器如何运行将直接影响 Servlet 的工作。


?


由图可以知道, Tomcat底层是Context, Context负责管理Servlet包装类Wrapper。


下面创建一个实例对象并调用 start 方法就可以很容易启动 Tomcat,我们还可以通过这个对象来增加和修改 Tomcat 的配置参数,如可以动态增加 Context、Servlet 等。我们就选择 Tomcat7 自带的 examples Web 工程,并看看它是如何加到这个 Context 容器中的。


//给 Tomcat 增加一个 Web 工程:
Tomcat tomcat = getTomcatInstance(); 
File appDir = new File(getBuildDirectory(), "webapps/examples"); 
tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath()); 
tomcat.start(); 
ByteChunk res = getUrl("http://localhost:" + getPort() + 
              "/examples/servlets/servlet/HelloWorldExample"); 
assertTrue(res.toString().indexOf("<h1>Hello World!</h1>") > 0);



上述代码是创建一个 Tomcat 实例并新增一个 Web 应用,然后启动 Tomcat 并调用其中的一个 HelloWorldExample Servlet,看有没有正确返回预期的数据。


//Tomcat 的 addWebapp 方法的代码如下:
public Context addWebapp(Host host, String url, String path) { 
       silence(url); 
       Context ctx = new StandardContext(); 
       ctx.setPath( url ); 
       ctx.setDocBase(path); 
       if (defaultRealm == null) { 
           initSimpleAuth(); 
       } 
       ctx.setRealm(defaultRealm); 
       ctx.addLifecycleListener(new DefaultWebXmlListener()); 
       ContextConfig ctxCfg = new ContextConfig(); 
       ctx.addLifecycleListener(ctxCfg); 
       ctxCfg.setDefaultWebXml("org/apache/catalin/startup/NO_DEFAULT_XML"); 
       if (host == null) { 
           getHost().addChild(ctx); 
       } else { 
           host.addChild(ctx); 
       } 
       return ctx; 
}



添加一个 Web 应用时将会创建一个 StandardContext 容器,并且给这个 Context 容器设置必要的参数(
url 代表这个应用在 Tomcat 中的访问路径; path 代表这个应用实际的物理路径) 其中最重要的一个配置是 ContextConfig,【ContextConfig监听器】继承了 【LifecycleListener 监听器接口】,它是在调用清单 2 时被加入到 StandardContext 容器中。 当 Context 容器初始化状态设为 init 时,添加在 Context 容器的 Listener 将会被调用。【ContextConfig监听器】将会负责整个 Web 应用配置文件的解析工作。最后将这个 Context 容器加到父容器 Host 中。


Servlet生命周期


Servlet生命周期分为四个部分: 实例化==>初始化==>执行处理==>销毁。


实例化


new , 服务器第一次被访问时,加载一个Servlet容器,只会被加载一次。


初始化


init:创建完Servlet容器后,会调用仅执行一次的init()初始化方法,用于初始化Servlet对象,无论多少台客户端在服务器运行期间访问都不会再执行init()方法。


可以在继承的GenericServlet这个抽象类中看到初始化方法:


public void init() throws ServletException {
    }



而在我们的Servlet类中应继承调用该方法:


public void init() throws ServletException {
        super.init();
    }



创建Servlet对象的时机:


  1. Servlet容器启动时:读取web.xml配置文件中的信息,构造指定的Servlet对象,创建ServletConfig对象,同时将ServletConfig对象作为参数来调用Servlet对象的init方法。
  2. 在Servlet容器启动后:客户首次向Servlet发出请求,Servlet容器会判断内存中是否存在指定的Servlet对象,如果没有则创建它,然后根据客户的请求创建HttpRequest、HttpResponse对象,从而调用Servlet 对象的service方法。
  3. Servlet Servlet容器在启动时自动创建Servlet,这是由在web.xml文件中为Servlet设置的<load-on-startup>属性决定的。从中我们也能看到同一个类型的Servlet对象在Servlet容器中以单例的形式存在。


执行处理


执行处理——service()方法


它是Servlet的核心,负责响应客户的请求。每当一个客户请求一个HttpServlet对象,该对象的Service()方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法相应的do功能。


HttpServlet的抽象类提供了doGet()、doPost()……等方法。对应了request请求的发送方法,与之相匹配:


    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }

    }
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_post_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }

    }



上面是操作性最高的部分。


销毁


销毁——destroy:在服务器关闭或重启时,Servlet会调用destroy方法来销毁,将Servlet容器标记为垃圾文件,让GC做回收处理。我们编写的Servlet是调用了GenericServlet抽象类的destroy方法:


@Override
    public void destroy() {
        super.destroy();
    }



Servlet工作原理


1、首先简单解释一下Servlet接收和响应客户请求的过程:
客户发送一个请求,Servlet是调用service()方法对请求进行响应,service()方法中对请求的方式进行了匹配。选择调用doGet,doPost等这些方法,然后再进入对应的方法中调用逻辑层的方法,实现对客户的响应。在Servlet接口和GenericServlet中是没有doGet()、doPost()等等这些方法的,HttpServlet中定义了这些方法,但是都是返回error信息,所以,我们每次定义一个Servlet的时候,都必须实现doGet或doPost等这些方法。


2、每一个自定义的Servlet都必须实现Servlet的接口,Servlet接口中定义了五个方法,其中比较重要的三个方法涉及到Servlet的生命周期,分别是上文提到的init(),service(),destroy()方法。GenericServlet是一个通用的,不特定于任何协议的Servlet,它实现了Servlet接口。而HttpServlet继承于GenericServlet,因此HttpServlet也实现了Servlet接口。所以我们定义Servlet的时候只需要继承HttpServlet即可。


3、Servlet接口和GenericServlet是不特定于任何协议的,而HttpServlet是特定于HTTP协议的类,所以HttpServlet中实现了service()方法,并将请求ServletRequest、ServletResponse 强转为HttpRequest 和 HttpResponse。


4、另外,Servlet是单例模式,线程是不安全的,因此在service()方法中尽量不要操作全局变量。但实际上,可以通过使用session和application来代替全局变量,只是会加大服务器负载。


Servlet处理请求的过程


  1. 客户端发送请求给服务器。
  2. 容器根据请求及web.xml判断对应的Servlet是否存在,如果不存在则返回404
  3. 容器根据请求及web.xml判断对应的Servlet是否已经被实例化,若是相应的Servlet没有被实例化,则容器将会加载相应的Servlet到Java虚拟机并实例化
  4. 调用实例对象的service()方法,并开启一个新的线程去执行相关处理。调用servce方法,判断是调用doGet方法还是doPost方法
  5. 业务完成后响应相关的页面发送给客户端。




学习更多JAVA知识与技巧,关注与私信博主(学习)学习JAVA 课件,
源码,安装包,还有最新大厂面试资料等等等


相关推荐

如何在HTML中使用JavaScript:从基础到高级的全面指南!

“这里是云端源想IT,帮你...

推荐9个Github上热门的CSS开源框架

大家好,我是Echa。...

前端基础知识之“CSS是什么?”_前端css js

...

硬核!知网首篇被引过万的论文讲了啥?作者什么来头?

整理|袁小华近日,知网首篇被引量破万的中文论文及其作者备受关注。知网中心网站数据显示,截至2021年7月23日,由华南师范大学教授温忠麟等人发表在《心理学报》2004年05期上的学术论文“中介效应检验...

为什么我推荐使用JSX开发Vue3_为什么用vue不用jquery

在很长的一段时间中,Vue官方都以简单上手作为其推广的重点。这确实给Vue带来了非常大的用户量,尤其是最追求需求开发效率,往往不那么在意工程代码质量的国内中小企业中,Vue占据的份额极速增长...

【干货】一文详解html和css,前端开发需要哪些技术?
【干货】一文详解html和css,前端开发需要哪些技术?

网站开发简介...

2025-02-20 18:34 yuyutoo

分享几个css实用技巧_cssli

本篇将介绍几个css小技巧,目录如下:自定义引用标签的符号重置所有标签样式...

如何在浏览器中运行 .NET_怎么用浏览器运行代码

概述:...

前端-干货分享:更牛逼的CSS管理方法-层(CSS Layers)

使用CSS最困难的部分之一是处理CSS的权重值,它可以决定到底哪条规则会最终被应用,尤其是如果你想在Bootstrap这样的框架中覆盖其已有样式,更加显得麻烦。不过随着CSS层的引入,这一...

HTML 基础标签库_html标签基本结构
HTML 基础标签库_html标签基本结构

HTML标题HTML标题(Heading)是通过-...

2025-02-20 18:34 yuyutoo

前端css面试20道常见考题_高级前端css面试题

1.请解释一下CSS3的flexbox(弹性盒布局模型),以及适用场景?display:flex;在父元素设置,子元素受弹性盒影响,默认排成一行,如果超出一行,按比例压缩flex:1;子元素设置...

vue引入外部js文件并使用_vue3 引入外部js

要在Vue中引入外部的JavaScript文件,可以使用以下几种方法:1.使用``标签引入外部的JavaScript文件。在Vue的HTML模板中,可以直接使用``标签来引入外部的JavaScrip...

网页设计得懂css的规范_html+css网页设计

在初级的前端工作人员,刚入职的时候,可能在学习前端技术,写代码不是否那么的规范,而在工作中,命名的规范的尤为重要,它直接与你的代码质量挂钩。网上也受很多,但比较杂乱,在加上每年的命名都会发生一变化。...

Google在Chrome中引入HTML 5.1标记

虽然负责制定Web标准的WorldWideWebConsortium(W3C)尚未宣布HTML5正式推荐规格,而Google已经迁移到了HTML5.1。即将发布的Chrome38将引入H...

HTML DOM 引用( ) 对象_html中如何引用js

引用对象引用对象定义了一个同内联元素的HTML引用。标签定义短的引用。元素经常在引用的内容周围添加引号。HTML文档中的每一个标签,都会创建一个引用对象。...

取消回复欢迎 发表评论: