看着Tomcat源码,写服务器(第二天)

这篇具有很好参考价值的文章主要介绍了看着Tomcat源码,写服务器(第二天)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 看着Tomcat源码,写服务器

Q: 为什么需要使用Servlet?

A: Servlet是一种Java编程语言的技术,用于构建动态Web应用程序。它可以处理客户端发送的请求并生成相应的响应。使用Servlet可以实现与数据库的交互、数据处理、用户身份验证等功能。此外,Servlet还具有可扩展性和可重用性,可以轻松地进行开发和维护。因此,使用Servlet可以提升Web应用程序的性能和功能,使其更加强大和灵活。

Q: 如果没有servlet会怎么样?

A: 在没有servlet的情况下,Web应用程序将无法处理动态内容和交互式功能。servlet是一种服务器端的Java程序,用于处理HTTP请求和响应。它可以与数据库进行交互,生成动态的网页内容,并处理用户提交的表单数据。因此,没有servlet的话,Web应用程序将无法实现与用户的交互,无法获取和显示动态数据,也无法与数据库进行通信。这将严重限制Web应用程序的功能和灵活性。

Q: servlet和http协议之间有着什么关联?

A: servlet是一种用于处理HTTP请求和响应的Java技术。它可以被看作是一种在服务器端运行的小程序,通过HTTP协议与客户端进行通信。HTTP协议则是一种用于在网络上传输超文本的协议。它定义了客户端和服务器之间的通信规则和格式。因此,可以说servlet是基于HTTP协议的一种技术,用于实现服务器端的业务逻辑处理和响应客户端的请求。

Q: 为什么说servlet实际上是一个接口呢?

A: servlet是Java编程语言中的一个规范,它定义了一种在Web服务器上运行的组件的行为和功能。简而言之,servlet提供了一种处理HTTP请求和生成HTTP响应的方式。它可以被认为是一个用于构建Web应用程序的基础框架。通过实现servlet接口,开发人员可以编写自己的servlet类,并根据自己的需求来处理客户端的请求和生成响应。因此,servlet实际上是一个接口,它为开发人员提供了一种定义和实现自己的Web应用程序的方式。

核心概念

  • Servlet容器 :用于提供HTTP请求给Servlet的环境。它负责接收和处理来自客户端的请求,并将请求传递给相应的Servlet进行处理。 Servlet容器还负责管理Servlet的生命周期,包括初始化Servlet、调用Servlet的服务方法以及销毁Servlet的过程。
  • Servlet接口 :所有Servlet都必须实现的接口,它定义了Servlet的生命周期方法(init, service, destroy)。这些方法分别在Servlet被初始化、每次接收到客户端请求时以及Servlet被销毁时被调用。通过实现Servlet接口,开发人员可以编写自己的Servlet类,并在其中实现业务逻辑。

此外,Java Servlet API 中还有几个其他重要的组件,用于各种目的,例如处理会话、管理请求和响应头以及处理 URL 映射。这些组件为使用 Java Servlet 技术开发 Web 应用程序提供了强大而灵活的平台。

重要组件

  • PrimitiveServlet :示例 Servlet,用于测试容器。
  • Servlet 生命周期方法
  • init() :当servlet首次初始化时调用此方法。它用于执行任何必要的设置或初始化任务。
  • service() :该方法负责处理发送到servlet的请求。它处理servlet的逻辑并确定如何响应每个请求。
  • destroy() :当servlet即将被销毁时调用此方法。它用于清理servlet使用的任何资源并执行任何必要的关闭任务。
  • ServletRequest 和 ServletResponse :Servlet 使用的对象,封装请求和响应。

下面还有俩不怎么需要去记的生命周期:

  • thread_safe():Servlet 被设计为线程安全的,这意味着它可以同时处理多个请求。这是通过使 Servlet 容器创建多个 Servlet 实例,并在不同的线程中调用 service() 方法来实现的。
  • session() :Servlet 还可以管理用户会话,允许跨多个请求跟踪用户特定的数据。Servlet 容器提供了用于创建、访问和管理用户会话的 API。

接下来我会写两个应用程序去带你们回忆它们:

应用程序 1

  • 功能:处理简单的 Servlet 和静态资源,不调用 init 和 destroy 方法。
  • 组件:HttpServer1, Request, Response, StaticResourceProcessor, ServletProcessor1, Constants。

需要添加一个关于servlet的pom依赖:

    <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>compile</scope>
        </dependency>

代码

Request.java 和 Response其实和之前差不多,只不过实现了servlet的子接口会有一些生成的其他方法,去阅读一下代码

small_http:

git clone https://github.com/MrKrabXie/writeHttpServer.git
process
package crab2;

import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;

public class ServletProcessor1 {
  public void process(Request request, Response response) {
    // 获取请求的uri
    String uri = request.getUri();
    // 取得uri中"/"后面的字符串作为servletName
    String servletName = uri.substring(uri.lastIndexOf("/") + 1);
    URLClassLoader loader = null;

    try {
      // 创建一个URLClassLoader
      URL[] urls = new URL[1];
      URLStreamHandler streamHandler = null;
      File classPath = new File(Constants.WEB_ROOT);
      // 创建仓库的url
      // 这个url创建方法参考了org.apache.catalina.startup.ClassLoaderFactory类中的createClassLoader方法
      String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString();
      // 生成URL的方法取自org.apache.catalina.loader.StandardClassLoader类中的addRepository方法
      urls[0] = new URL(null, repository, streamHandler);
      loader = new URLClassLoader(urls);
    } catch (IOException e) {
      System.out.println(e.toString());
    }

    // 加载servlet类
    Class myClass = null;
    try {
      myClass = loader.loadClass(servletName);
    } catch (ClassNotFoundException e) {
      System.out.println(e.toString());
    }

    Servlet servlet = null;
    try {
      // 创建servlet实例
      servlet = (Servlet) myClass.newInstance();
      // 在服务请求和响应上调用servlet
      servlet.service((ServletRequest) request, (ServletResponse) response);
    } catch (Exception e) {
      System.out.println(e.toString());
    } catch (Throwable e) {
      System.out.println(e.toString());
    }
  }
}

首先,我们看到类ServletProcessor1,其主要功能是处理Request和Response。在这个类中,一系列的try和catch块尝试创建一个URLClassLoader去加载对应的Servlet并执行服务

这段代码首先从Request中获取URI,然后提取出servletName,即"/"后面的字符串。然后创建一个URLClassLoader,用于加载servlet的类文件。创建ClassLoader需要的repository是从文件系统中获取的WEB_ROOT目录。
经过一系列的加载和实例化后,得到了我们的Servlet实例。然后,将请求和响应进行服务化处理,即servlet.service(request,response)。

package crab2;
import java.io.IOException;
public class StaticResourceProcessor {
  // 处理方法,接受请求和响应为参数
  public void process(Request request, Response response) {
    try {
      // 响应发送静态资源
      response.sendStaticResource();
    }
    // 捕获并打印可能出现的IOException异常
    catch (IOException e) {
      e.printStackTrace();
    }
  }
}

如上

import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;

// 实现了 Servlet 接口的服务器组件,可以接收和响应来自客户端的请求
public class PrimitiveServlet implements Servlet {

  // 初始化函数,在 Servlet 生命周期中只会被调用一次
  public void init(ServletConfig config) throws ServletException {
    System.out.println("初始");
  }

  // service 函数,每次接收到客户端请求时被调用
  public void service(ServletRequest request, ServletResponse response)
          throws ServletException, IOException {
    System.out.println("来自 service 函数");
    PrintWriter out = response.getWriter();
    String errorMessage = "HTTP/1.1 404 文件未找到\r\n" +
            "Content-Type: text/html\r\n" +
            "Content-Length: 23\r\n" +
            "\r\n" +
            "<p>hi rose.<\\p>\r\n" +
            "<p>it is blue..<\\p>";
    out.println(errorMessage);
  }

  // 销毁函数,在 Servlet 生命周期结束时被调用
  public void destroy() {
    System.out.println("销毁");
  }

  // 返回 Servlet 的信息,此方法可选
  public String getServletInfo() {
    return null;
  }

  // 返回 ServletConfig 对象,它包含了 Servlet 的初始化和启动配置
  public ServletConfig getServletConfig() {
    return null;
  }
}

这段代码定义了一个名为PrimitiveServlet的类,并实现了Servlet接口。
init函数是一个初始化函数,Servlet在其生命周期中只调用一次这个函数。

service函数在每次接收到客户端请求时被调用。request和response对象分别用来接收和响应客户端的请求。

destroy函数在Servlet的生命周期结束时被调用。

getServletInfo函数返回Servlet的信息,这个方法是可选的。
getServletConfig函数返回一个ServletConfig对象,这个对象包含了Servlet的初始化和启动配置。

应用程序 2

思考:

第一个应用程序有一个严重的问题。在 ServletProcessor1 类的 process 方法,你向上转换
Request 实例为 javax.servlet.ServletRequest,并作为第一个参数传递给
servlet 的 service 方 法 。 你 也 向 下 转 换Response 实 例 为
javax.servlet.ServletResponse,并作为第二个参数传递给 servlet 的 service 方法。

try {
servlet = (Servlet) myClass.newInstance();
servlet.service((ServletRequest) request,(ServletResponse) response);
}

这会危害安全性。知道这个 servlet 容器的内部运作的 Servlet 程序员可以分别把
ServletRequest 和 ServletResponse 实 例 向 下 转 换 为 Request 和
Response,并调用他们的公共方法。拥有一个 Request实例,它们就可以调用 parse
方法。拥有一个 Response 实例,就可以调用 sendStaticResource 方法。

讨论
  • 场景: 是在, 老开发的年代, 分别需要用lib包去作为传递桌面端一些内部类,又不想一些桌面端的代码信息泄露, 毕竟现在都是web接口开发就不太容易有这顾虑和问题, 大家这里看看就好。 知道正常接口是向上转。而不能让使用者去向下转就行。
  • 改进:增加了安全性,引入了 facade 类(RequestFacade 和 ResponseFacade)以保护内部实现。
  • 组件:HttpServer2, ServletProcessor2(使用 façade 类处理请求和响应)。
  • 具体原因: 开放内部操作或过多的公有方法可能会影响应用的安全性。如果程序员可以获取 ServletRequest 和 ServletResponse 对象,并将它们向下转型为 crab.Request 和 crab.Response,那么他们就能够调用这些类中的公有方法。
    例如,parse 方法可能会被误用来解析非法或有害的请求,sendStaticResource 方法可能被用来输出不应该被访问的资源。这些都可能导致安全问题。
    这就是为什么通常要坚持最小权限原则(Principle of Least Privilege),只有那么多的权限才能完成工作是必要的。特别是对外部用户,你应该尽可能地限制他们能够访问的方法或资源。这也包括设计 API 和暴露服务时考虑到的,你应该只提供必要的接口,不要为了方便而公开过多的内部操作。

这里贴部分代码,解释一下思路就是: 可以通过默认的访问修饰符去控制,也可以通过一个设计模式进行优化:
下面代码,对比他们属性和方法。猜设计模式是什么设计模式。


// 创建公用的请求类
public class Request implements ServletRequest {
  // 定义输入流
  private InputStream input;
  // 定义uri
  private String uri;
  // 创建构造器,接受输入流参数
  public Request(InputStream input) {
    this.input = input;
  }
  // 获取uri的方法
  public String getUri() {
    return uri;
  }
public class RequestFacade implements ServletRequest {  private ServletRequest request = null;  public RequestFacade(Request request) {
    this.request = request;
  }

  public Object getAttribute(String attribute) {
    return request.getAttribute(attribute);
  }

  public Enumeration getAttributeNames() {
    return request.getAttributeNames();
  }

是使用门面模式(Facade Pattern)的方法来提升安全性。在最初的设计里,当 ServletRequest 对象被传递给 service 方法时,它会被向下转换为 Request 对象。这样做的问题是 service 方法现在可以调用 Request 中所有的公有方法,包括一些可能导致安全问题的方法。
为了解决这个问题,引入了 RequestFacade 类。这个类实现了 ServletRequest 接口,自身包含一个 Request 的引用,但只暴露出 ServletRequest 接口中的方法,而不需要把 Request 对象本身暴露出来。这样一来,尽管开发者仍可以对 ServletRequest 进行向下转型得到 RequestFacade,但他们只能通过 ServletRequest 接口调用对应的公开方法,无法访问到 Request 类内部的方法。
这样,我们就隐藏了 Request 的内部实现,避免了该类对象的滥用,也就提高了系统的安全性。比如,你提到的 parseUri 方法,就因为它不能从外部访问而变得更安全了。

总结

本章通过构建简单的 Servlet 容器,介绍了 Servlet 编程的基础,为构建完整的 Tomcat 容器奠定了基础。文章来源地址https://www.toymoban.com/news/detail-773120.html

到了这里,关于看着Tomcat源码,写服务器(第二天)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 一台电脑同时安装多个tomcat服务器教程,window同时安装tomcat7、tomcat8、tomcat9三个服务器教程

    A. 解释为什么有时需要同时安装多个Tomcat服务器 应用程序隔离:当你需要在同一台设备上运行多个独立的应用程序时,每个应用程序可能需要使用不同的Tomcat配置和环境。通过同时安装多个Tomcat服务器,可以实现应用程序之间的隔离,确保它们互不干扰。这种隔离可以防止一

    2024年02月13日
    浏览(59)
  • IDEA搭建Java Web项目及添加Web框架支持和配置Tomcat服务器(2023最新版)

     File — New — Project Java — Project SDK中选择自己的版本(这里采用1.8) —点击Next 此项不选 直接点击Next 设置项目名称之后 点击 Finish 鼠标右键项目名 — Add Frameworks Support   勾选第一项 Web Application — 点击 OK 出现web目录后即为Web框架支持添加成功   点击Add Configruation 点击添加

    2024年02月13日
    浏览(82)
  • 重启tomcat-Tomcat服务器怎么重启?

    Tomcat服务器重启的办法: 第一步:使用cmd进入dos界面 第二步:进入Tomcat安装目录 C:UsersAdministrator.MS-E: E:cdapache-tomcat–windows-apache-tomcat-i E:apache-tomcat–windows-apache-tomcat-in 到bin目录之后,先关闭原来运行的Tomcat服务器 第三步:关闭方法:执行shutdown.bat指令 E:apache-tomcat–windows

    2024年02月04日
    浏览(42)
  • Tomcat配置报错:HTTP状态 500 - 内部服务器错误org.apache.jasper.JasperException: java.lang.ClassNotFoundException

    HTTP状态 500 - 内部服务器错误 类型 异常报告 消息 org.apache.jasper.JasperException: java.lang.ClassNotFoundException: org.apache.jsp.index_jsp 描述 服务器遇到一个意外的情况,阻止它完成请求。 例外情况 org.apache.jasper.JasperException: org.apache.jasper.JasperException: java.lang.ClassNotFoundException: org.apache.j

    2024年02月07日
    浏览(75)
  • 服务器安装Tomcat

    下载Tomcat 下载地址在这: Tomcat官网  下载完成以后把压缩包上传到服务器中(我传到了www/java),进行解压(解压到),如果没有进行指定解压到哪里,默认是到root文件夹中 然后进入到bin文件夹里。进行启动可!  运行 结束运行

    2024年02月12日
    浏览(45)
  • 配置Tomcat服务器

    访问tomcat主页的时候,输入的是localhost:8080,说明tomcat的端口是8080,那么怎么修改端口号呢? 我们要先认识配置文件 用浏览器打开tomcat下conf子目录server.xml 这一句的意思是通过8005端口发送大写的“SHUTDOWN”,会关闭服务器 这里告诉我们端口是8080;协议是http1.1;connectionTim

    2024年03月09日
    浏览(45)
  • Tomcat服务器

    一、基本概念 1.1硬件服务器:通常是指在互联网上具有独立IP的计算机,通常配置比较高。比如我们自己的计算机也可以作为服务器使用(只不过配置较低) 1.2软件服务器:就是一个计算机程序,比如MySQL服务器软件,tomcat服务器软件。服务器软件分为很多类型,比如:ftp服

    2024年02月06日
    浏览(37)
  • Tomcat 服务器配置

                目录 一:server.xml   1.Server  2.Service 3 .Executo 4 .Connector 完整的配置如下: 5.Engine 6 .Host 7.Context 二:tomcat-users.xml              Tomcat 服务器的配置主要集中于 tomcat/conf 下的 catalina.policy 、 catalina.properties、 context.xml 、 server.xml 、 tomcat-users.xml 、 web.xml 文件。    

    2024年02月11日
    浏览(40)
  • 安装Tomcat服务器

    tomcat需要下载JDK,因为tomcat是Java语言编写的,运行在Java虚拟机上。 以下是tomcat对应JDK版本,安装tomcat需要安装对应的JDK版本 我这里安装的是9版本,则需要安装1.8版本以上的JDK 进入JDK中文官网https://www.oracle.com/cn/java/technologies/downloads/#java8-windows 登录账号,没有就创建一个

    2024年03月09日
    浏览(54)
  • web服务器(Tomcat)

    目录 一、web服务器 1. 常见web服务器 2. web服务器简介 二、 Apache Tomcat服务器 1. Tomcat服务器简介 2. Tomcat服务器基本使用 3. 启动tomcat常见问题 (1)启动tomcat控制台乱码 (2)启动tomcat闪退问题 (3)启动报错 4.  如何关闭Tomcat服务器 5. Tomcat文件目录介绍 6. Tomcat服务器部署项目

    2024年02月15日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包