Java内存马基础(一)--三大件(Servlet、Filter、Listener)

文摘   2024-07-08 11:41   北京  
Java Web 三大件:


  在讲Tomcat 之前,先说讲一讲Java Web 三大件,也就是Servlet、Filter、  Linstener,当 Tomcat 接收到请求后,会依次经过 Listener -> Filter -> Servlet

01

Servlet

Servlet 简介:

Servlet 是一个用Java 编写的程序,此程序在服务器上运行以处理客户端请求。

优点:

  • 高效:支持缓存&多线程

  • 方便:Servlet 提供了大量的实用工具例程,例如自动的解析和解码HTML表单数据,读取和设置HTTP头、处理Cookie、跟踪会话状态等。

  • 功能强大:以Java API 作为后盾

  • 可移植性好:用Java语言编写,可以在服务器端运行


执行过程:

  1. 客户端发送请求至服务器端;

  2. 服务器端遍历web.xml中的url-pattern,找到Servlet;

  3. 执行service() 方法,service解析用户请求,匹配对应方法

  4. Servlet方法,生成响应内容并将其传给服务器。相应内容动态生成,通常取决于客户端的请求。

  5. 服务器将响应返回给客户端。

02

Servlet 原理


Servlet 体系结构:
ServletConfig 接口:

用来封装web.xml 中对当前Servlet的配置信息

getinitParameter() ----可以获取初始化参数web.xml:<init-param>    <para-name/>    <para-value/></init-param>
ServletContext:

代表当前Servlet上下文运行的环境,用于获取其来自容器的信息的方法。

ServletContext 对象也被称之为context 域对象。    setAttribute(name,value)    getAttribute(name)    removeAttribute(name)//利用ServletContext 对象读取资源
  • setAttribute(name,value)

    • 这个方法用于将属性存储到ServletContext对象中,可以使用name参数指定属性的名称,并使用value 参数指定属性的值。存储的属性将在整个应用程序范围内可见,可以在应用程序的任何Servlet中访问。例如servletContext.setAttribute('key',value) 会将一个名为key的属性设置指定的值。

  • getAttribute(name)

    • 这个方法用于从servletContext 对象中获取指定属性的值。可以通过name 参数指定要获取的属性的名称。获取的属性值可以在整个应用程序范围内共享,并且可以在应用程序的任何Servlet中访问。例如Object value = servletContext.getAttribute(key) 会获取名为key的属性的值,并将其存储在变量 value 中。


  • removeAttribute(name)

    • 这个方法用于从ServletContext 对象中移除一个属性。可以使用name参数指定要移除的属性的名称。移除后,该属性将不再应用程序中可用。例如,servletContext.removeAttribute('key') 会从ServletContext 对象中移除名为key的属性。


package org.example;import java.io.*;import javax.servlet.*;import javax.servlet.annotation.WebServlet;import javax.servlet.http.*;@WebServlet("/myServlet")public class MyServlet extends HttpServlet {    public void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        // 获取ServletContext对象        ServletContext context = getServletContext();        // 设置属性        context.setAttribute("message", "Hello, World!");        // 获取属性        String message = (String) context.getAttribute("message");
// 输出属性值 response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html><body>"); out.println("<h1>Message from ServletContext: " + message + "</h1>");
out.println("</body></html>"); // 移除属性 context.removeAttribute("message"); }}
  • ServletRequest:为Servlet所发送的请求,用ServletRequest封装

    • setAttribute

    • getAttribute    

    • removeAttribute

    • getParameter

  • ServletResponse:Servlet对客户端所做的响应,用ServletResponse 描述

    • getWriter

    • setContentType

    • sendRedirect

JavaServlet是运行在Web服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 Http 客户端的请求和 Http服务器上的数据库或应用程序之间的中间层。

请求的处理过程:

客户端发起一个 http 请求,比如 get 类型。Servlet 容器接收到请求,根据请求信息,封装成HttpServletRequest 和 HttpServletResponse 对象。这步也就是我们的传参。Servlet 容器调用HttpServlet 的 init 方法,init方法只在第一次请求的时候被调用。Servlet 容器调用 service() 方法。service方法根据请求类型,这里是get类型,分别调用doGet或者doPost方法,这里演示的是调用doGet方法。业务处理完成后返回给Servlet容器,然后容器将结果返回给客户端。容器关闭的时候会调用 destory方法。

package com.example.demo;import javax.servlet.*;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import java.io.IOException;@WebServlet("/servlet")public class ServletTest implements Servlet {
    @Override    public void init(ServletConfig servletConfig) throws ServletException {
    }
    @Override    public ServletConfig getServletConfig() { return null;


    }    @Override    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {    }    @Override    public String getServletInfo() {        return null;    }    @Override    public void destroy() {    }}

Servlet可用于攻击的点:

  • service() :在 Servlet中,主要的请求处理逻辑通常在service() 方法中实现,如果开发者没有正确验证和过滤用户的输入,攻击者会利用此漏洞执行SQL注入、xss攻击

import javax.servlet.*;import javax.servlet.annotation.WebServlet;import javax.servlet.http.*;import java.io.*;import java.sql.*;
@WebServlet("/login")public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");String password = request.getParameter("password");
try {Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase""username""password");
Statement stmt = conn.createStatement();
String query = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'";
ResultSet rs = stmt.executeQuery(query);
if (rs.next()) {// 登录成功
response.getWriter().println("登录成功");
} else {// 登录失败
response.getWriter().println("用户名或密码错误");

            }
conn.close(); } catch (SQLException e) {

e.printStackTrace();
}

}

}
  • 请求参数处理:Servlet通常通过请求对象(HttpServletRequest)来访问用户提交的参数。如果这些参数没有被正确的校验和过滤,攻击者可能会利用这些参数执行各种攻击,比如路径遍历、命令注入

  • 会话管理:如果Servlet在会话管理方面存在漏洞,攻击者可能会利用会话劫持、会话固定、会话破坏等技术,获取用户信息,冒充合法用户或执行其他恶意操作

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.*;


@WebServlet("/evil")
public class EvilServlet extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 获取当前会话HttpSession session = request.getSession();// 如果会话已经建立,则偷取会话ID并发送到恶意服务器if (session != null) {
String sessionId = session.getId();
sendStolenSessionIdToMaliciousServer(sessionId);
}
// 重定向用户到正常页面response.sendRedirect("/normalPage.jsp");
}


private void sendStolenSessionIdToMaliciousServer(String sessionId) {// 将会话ID发送到恶意服务器的代码System.out.println("Stolen session ID: " + sessionId);// 恶意服务器的URLString maliciousServerUrl = "http://maliciousserver.com/steal-session";// 发送会话ID到恶意服务器 }
}
  • 文件上传:如果Servlet用于处理文件上传功能,开发人员没有正确的验证上传文件的内容和类型,攻击者可能会上传包含恶意代码的文件,并在服务器上执行该代码

import javax.servlet.*;import javax.servlet.annotation.WebServlet;import javax.servlet.http.*;import java.io.*;import java.nio.file.*;


@WebServlet("/upload")@MultipartConfigpublic class FileUploadServlet extends HttpServlet {


protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Part filePart = request.getPart("file");
String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString();
InputStream fileContent = filePart.getInputStream();
Files.copy(fileContent, Paths.get("/uploads/" + fileName), StandardCopyOption.REPLACE_EXISTING);
response.getWriter().println("文件上传成功");    }}

03

Servlet 生命周期


  • 服务器启动时(web,xml 中配置  load-on-startup=1,默认为0)或者第一次请求该servlet时,就会初始化一个 Servlet 对象,也就是会执行初始化方法init(ServletConfig servletConfig) 

  • servlet对象去处理所有客户端请求,在 service(ServletRequest servletRequest, ServletResponse servletResponse) 方法中执行。

  • 服务器关闭时,销毁这个servlet对象,执行destroy() 方法。

  • 由 JVM 进行垃圾回收

04

Filter


filter也称之为过滤器,是对Servlet技术的一个补充,其主要功能是在HttpServletRequest 到达Servlet 之前,拦截客户的HttpServletRequest,根据需要检查 HttpServletRequest,也可以修改 HttpServletRequest 头和数据;在HttpServletResponse到达客户端之前,拦HttpServletReponse,根据需要检查HttpServletResponse,也可以修改HttpResponse头和数据

import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;

@WebFilter("/secured/*")public class IPFilter implements Filter {

// 允许访问的IP范围private static final String ALLOWED_IP_RANGE = "192.168.0.";

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) res;// 获取请求的IP地址String ipAddress = request.getRemoteAddr();

// 检查IP地址是否在允许范围内if (ipAddress.startsWith(ALLOWED_IP_RANGE)) {// 如果是允许的IP范围,则允许请求通过chain.doFilter(req, res); } else {// 如果不在允许的IP范围内,则返回403错误response.setStatus(HttpServletResponse.SC_FORBIDDEN);response.getWriter().println("Forbidden"); }

}


public void init(FilterConfig filterConfig) throws ServletException {// 初始化过滤器 }
public void destroy() {// 销毁过滤器 }}

这是一个简单的filter 案例,其中使用了一个doFilter 方法,该方法会对传递进来的IP进行检查,如果符合条件则放行到servlet或者是其他filter,如果不在允许的IP范围内则返回403。

doFilter 方法接收3个参数:

  • ServletRequest req:代表客户端发来的请求。这是一个ServletRequest 对象,其中包含了请求的所有信息,比如请求的url、请求头,请求方法。

  • ServletReponse res:代表要发送给客户端的响应。这是一个ServletResponse 对象,其中包含了与响应有关的所有信息,比如状态码,响应头,响应体等。

  • FilterChain chain:这是一个FilterChain 对象,代表了过滤器链。FilterChain 中包含了当前Filter之后的所有Filter以及目标Servlet的调用。调用FilterChain 的 doFilter 方法可以将请求传递给下一个Filter 或者目标 Servlet

import javax.servlet.*;import javax.servlet.annotation.*;import javax.servlet.http.*;import java.io.*;

@WebServlet("/hello")public class HelloServlet extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取请求参数String name = request.getParameter("name");
// 在响应中输出欢迎消息PrintWriter out = response.getWriter();out.println("<html>");out.println("<head><title>Hello Servlet</title></head>");out.println("<body>");out.println("<h1>Hello, " + name + "!</h1>");out.println("</body></html>"); }}
@WebFilter("/hello")class ModifyRequestFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {// 初始化方法 }
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {// 将请求修改为添加一个额外的参数

HttpServletRequest request = (HttpServletRequest) req;String modifiedName = request.getParameter("name") + " (modified)";
// 创建一个新的HttpServletRequestWrapper,用于修改请求参数

HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(request) {@Overridepublic String getParameter(String name) {if ("name".equals(name)) {return modifiedName; }return super.getParameter(name); } };// 继续传递修改后的请求到目标Servletchain.doFilter(requestWrapper, res); }
public void destroy() {// 销毁方法 }}

这个案例中,首先创建一个自定义的Servlet,用来处理来自于客户端的请求,在这个Servlet中,通过doGet方法接收来自于客户端的Get请求,参数是name,经过自定义的Filter过滤器时,Filter对请求进行了修改,在name参数的后面拼接了(modified)。修改后的请求被传递给了Servlet。Servlet将修改后的name参数返回给了客户端。

最后是销毁方法,一般用于销毁加载的外部资源,例如文件对象,数据库对象,这里没有加载外部资源,所以没有写销毁方法内部。

注意这里说的是请求从Filter 传递给了 Servlet,而不是转发给Servlet, 这两者之间是有区别的,在Servlet容器中,请求的处理通常是通过一个Filter链来完成的,每个Filter都有机会对请求进行修改或处理,并决定是否将请求传递给下一个Filter或目标Servlet。这个传递的过程可以通过两种方式来实现:转发和链式调用

  • 转发(Forwarding):当一个Filter修改完请求后,它可以选择通过转发(forward)的方式将修改后的请求传递给下一个filter 或目标 Servlet。这样。被转发的请求会绕过原始的请求路径,直接传递给目标组件。这个过程类似于将请求从一个组件传递到另一个组件,但是请求路径会发生变化

  • 链式调用(Chain Invocation):另一种方式是通过调用FilterChain的doFilter 方法,将修改后的请求传递给下一个Filter或目标Servlet。这个过程是在同一个请求对象上进行的,不会改变请求的路径,请求会按照原来的路径继续传递。这样每个Filter都有机会对请求进行处理,并且可以在不改变请求路径的情况下传递给下一个组件。

知道这一点以后我们就可以想办法在目标的Filter前面自己创建一个Filter,这样的话我们就可以使用自己创建的Filter来执行命令,这种方案叫做"过滤器链劫持",在某种程度上也可以说是一种内存马。当一个Web应用程序允许一个用户添加自定义的Filter并控制他们的顺序时,攻击者可以通过注入恶意的Filter来拦截所有传入的请求,并执行任意操作,包括篡改请求等。这种攻击被称为"Filter Chain Hijacking"。

有一些可能允许自定义Filter的场景:

  • 开放平台或应用插件系统:一些开放平台或应用插件系统允许第三方开发者为平台或应用程序编写自定义插件或扩展,这些插件可能包含Filter用于对请求和响应进行自定义处理。

  • 定制化的web框架:一些web框架可能提供了灵活的拦截器,或Filter机制,允许开发者根据需求编写自定义的拦截器或Filter,以实现特定的业务逻辑或功能。

  • 中间件或应用服务器:一些中间件或应用服务器可能提供了Filter配置的功能,允许管理员或开发者定义一系列的Filter链,用于对请求和响应进行过滤处理,以满足特定的安全或性能要求

  • 定制化的网络安全应用:一些网络安全应用可能提供了自定义Filter的功能,用于实现特定的网络安全策略,例如防火墙,入侵检测系统(IDS)、反爬虫系统。

05

Filter 的生命周期


  • Filter的创建和销毁由Web容器负责:就像Servlet一样,Filter的创建和销毁是由Web容器负责的。当Web应用程序启动时,Web服务器会创建Filter的实例对象,并调用init方法进行初始化,Web容器卸载或服务停止时,Filter对象才被销毁。

  • 初始化过程:初始化的过程中,Web服务器会读取web.xml配置文件中的相关配置(当然也可以使用注解配置,使用@WebFilter("/*")可以对所有*开头的路径在访问的时候进行拦截),并将这些配置信息传递给Filter的init方法,以完成Filter对象的初始化功能。这样Filter对象可以在初始化的过程中根据配置进行一些准备工作,以完成后续的用户请求做好拦截准备。需要注意的是Filter对象只会创建一次,所以init方法也只会执行一次。

  • 销毁过程:在Filter对象被销毁之前,web容器会调用Filter的destory()方法。这个方法在Filter的生命周期中只执行一次。在destroy() 方法中,可以释放Filter使用的资源,释放数据库连接。

06

Filter 链




 多个Filter出现的时候组成了Filter链,Web应用服务器根据Filter在web.xml中的注册顺序来决定调用顺序。webx.xml中内容大致如下:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0">

<!-- Filter1 --><filter><filter-name>Filter1</filter-name><filter-class>com.example.Filter1</filter-class></filter><filter-mapping><filter-name>Filter1</filter-name><url-pattern>/*</url-pattern></filter-mapping>
<!-- Filter2 -->

<filter><filter-name>Filter2</filter-name><filter-class>com.example.Filter2</filter-class></filter><filter-mapping><filter-name>Filter2</filter-name><url-pattern>/*</url-pattern></filter-mapping></web-app>

当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain 对象,传递给该方法,通过判断FilterChain中是否还有Filter来决定后面是否调用 Filter还是将请求传递给Servlet。

07

Listener


Java监听器是一种用于监听并响应特定事件的组件。它的原理基于设计模式中的观察者模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象,当主题对象发生变化时,所有依赖于它的观察者都会得到通知并进行相应的处理。

事件源是触发事件的地方,例如文本框,按钮等。当事件触发后事件会被包装成事件对象,这个事件对象中包含了事件发生的相关信息,比如事件类型,触发时间等。然后事件对象会被传递给注册的监听器,监听器是一组实现了特定接口的类,他们定义了用于处理特定类型事件的方法。当监听器监听到事件对象后,会根据事件对象中的信息执行相应的监听器方法,例如修改界面状态、执行业务逻辑等。这样通过事件源,事件对象和监听器的协作,实现了对特定事件的监听和处理。

  • 事件源(Event Source):事件发生的地方或对象,可以触发某些特定事件,例如在图形化界面中的文本框、按钮,菜单。他们可以触发鼠标点击事件和键盘输入事件。

  • 事件对象(Event Object):当事件发生时,事件源会创建一个事件对象,用于描述事物发生时的具体信息,包括事件源、事件类型、事件发生的时间等。事件对象是一个包装了事件信息的对象。

  • 监听器(Listener):是一个接口,定义了监听特定类型事件的方法。开发人员可以实现这个接口,并将实现类注册到事件源上。当事件发生时,监听器会被调用,并执行相应的方法来处理事件。

  • 监听器方法(Listener Method):是监听器接口中定义的方法,用于处理特定类型的事件。当事件发生时,事件源会调用监听器的方法,并将事件对象作为参数传递给监听器。监听器可以根据事件对象中的信息来执行相应的操作,例如修改界面状态、执行业务逻辑等。

package com.example.demo;import java.awt.*;import java.awt.event.*;



public class ButtonExample extends Frame { public ButtonExample(){ super("Button Example"); // create a button Button button = new Button("Click Me"); // add action linstener to button add(button); // create a click Listener button.addActionListener(new ButtonClickListenner()); // set size of frame setSize(300,200); setVisible(true); } // inner Class ButtonClickListenner class ButtonClickListenner implements ActionListener{ public void actionPerformed(ActionEvent e){ System.out.println("Button Clicked!"); } } public static void main(String[] args){ new ButtonExample(); }}

这是一个简单的案例,可以看到在代码运行的时候,点击按钮就会触发事件,

08

Tomcat 基础


Tomcat 是一个开源的,轻量级的Java Servlet容器,Apache软件基金会的一个项目。实现了多种Java技术,提供了一个可用于开发和部署Java Web的环境。

Tomcat 主要特点包括:

  • Servlet 容器:Tomcat 是一个Servlet容器,能够运行java Servlet 和JavaServer Pages(JSP页面)等java web组件。它接收Http请求,并调用相应的Servlet来处理请求,然后返回响应给客户端。

  • 轻量级:Tomcat 是一个轻量级的用来部署Java web 的应用服务器,具有快速部署的特点,核心非常精简,只包含了必要的功能和组件

  • 开源:Tomcat是一个开源项目

  • 可扩展性:Tomcat支持通过插件和扩展来扩展其功能。使用者可以通过额外组件或模块来增强Tomcat功能。

  • 跨平台:Tomcat是跨平台的,可以在多个操作系统上运行。包括Win、Linux、macOS

Tomcat 工作流程:

Tomcat 容器请求处理流程:

 Tomcat中包含2个组件(Web应用服务器、Servlet容器)和一个Servlet API。因为Tomcat实现了Servlet容器的功能,所以需要提供ServletAPI的支持,使得开发人员可以合理的编写符合Servlet规范的工作类,并在Tomcat中运行,这个Servlet API定义了加载到Servlet 容器中类的规范和方法。

  Servlet规范包含了Http服务器接收到Http请求后将其交给Servlet容器处理的流程。servlet容器会根据i请求中的URL或其他信息适当的选择Servlet来处理请求。Servlet容器来通过Servlet接口调用具体的业务类,执行与请求相关的逻辑,并生成响应发送给客户端。除了这些之外还有其他更多的方面,比如Servlet生命周期管理、请求处理机制、线程安全性。Servlet规范不仅仅局限于Http请求处理,还包括处理其他类型请求的能力,如Https请求、WebSocket请求等。

09

Tomcat 架构


概述

它的核心主要由4个部分组成:Server(服务器)、Service(服务,)Connector(连接器)、Container(容器)。这四部分共同承担着Tomcat 的主要任务。

server

Tomcat Server 是整个 Tomcat 服务器的控制中心,负责管理整个实例的生命周期和服务。它提供接口以便其他程序访问Service 集合,并维护所有Service 的生命周期,包括初始化、终止服务以及路由请求给相应的Service。Tomcat 通常只有一个Server,每个Server 包含至少一个Service 组件,用于提供具体的服务

Service

Service 主要负责关联Connector 和 Container,以及管理他们的生命周期。每个Service 可以包含多个Connector,并且只能有一个Connector 容器。在Tomcat 中,Service接口的标准实现类是StandardService,它实现了Service 接口和Lifecycle 接口,这使得它能够控制其下的组件的生命周期。

Conector

Connector 是 Tomcat 中四个核心组件之一,主要负责处理客户端的Request连接请求,并将其转化为Tomcat Request请求对象,然后交由Container 组件处理。

Connector 内部的三个设计组件:

  • EndPoint:负责网络通信,将字节流传递给Processor。

  • Processor:处理字节流生成 TomcatRequest 对象,并将其传递给容器

  • Adapter:将Tomcat Request 对象转化成ServletRequest对象,传递给容器

Connector 的三个主要功能分别是:

  • 负责处理客户端的连接请求,建立网络连接

  • 将接收到的字节流解析处理,封装成Request 和Response 对象,以便于后续处理

  • 将Request 对象转换成ServletRequest,以便于容器进一步处理


所以说 EndPoint、Processor 和 Adapter 是 Connector 内部实现这三个主要功能的关键组成部分。它们共同协作,使得Connector 能够有效地处理客户端的连接请求,解析处理应用层协议,并将请求转发给容器进一步处理。这些组件构成了Connector 内部的工作流程。负责实现 Connector 的核心功能。

10

Adapter


Adapter 组件是除了四大核心组件之外的非核心组件,在Tomcat 中的作用是将Tomcat 内部的Request 对象转换成标准的ServletRequest 对象,以便于能够和标准的Servlet 规范进行兼容,并能够在Servlet容器中正常处理请求。Adapter 的主要功能是在Tomcat 内部与外部Servlet容器之间建立桥梁,确保Tomcat 可以与外部Serrvlet容器进行交互。 

实际上 Connector 中也确实有和  Adapter 类似的功能----- Request 对象转换成标准的 ServletRequest 对象。

因为Connector 是负责处理客户端的连接请求,并将其转化成Tomcat 的Request 对象。在某种程度上,Connector 的处理流程中已经涉及到将请求 转化成Tomcat 的Request 对象。

然而,Connector 中的 Adapter 不仅仅是将请求对象转化成ServletRequest 对象,而是更广泛的负责与 Servlet 容器进行交互。它的主要职责是将Tomcat 内部的Request 对象转化成标准的ServletRequest对象,并将请求传递给Servlet 容器进行处理。因此,Connector 中的Adapter 在处理请求的时候可能还会执行其他操作,比如对请求进行进一步的处理或转发。

虽然两者在功能上有些重叠,但两者的主要目标和职责不同。Connector 中的 Adapter 更侧重于与外部Servlet 容器的交互,而不仅仅是简单的讲请求对象转换成标准的ServletRequest 对象。

总结一下:

  • Adapter 负责在Tomcat 内部将Tomcat 的Request 对象转换成标准的ServletRequest 对象,以便内部的Servlet 容器能够正确的处理请求。

  • Connector 负责在Tomcat 外部处理客户端的连接请求,并将其转换成Tomcat 的Request 对象,同时也负责将Tomcat 的Reponse 对象转换成标准的ServletResponse,以便外部的Servlet 容器能够正确的处理响应。


这里对内部的Servlet 容器和外部的Servlet容器做一个说明:

  • Tomcat 中的Servlet 容器指的是Tomcat 内部的组件,负责运行和管理Servlet,并处理客户端的HTTP 请求。在Tomcat 中,这个组件通常是指 Catalina Servlet 容器。

  • Adapter是在 Tomcat 内部将 Tomcat 的Request 对象转换成标准的ServletRequest 对象的组件。

  • Connector 是负责处理客户端的连接请求,并与外部的Servlet容器进行交互的组件。外部的Servlet容器是独立于 Tomcat之外的其他Servlet容器,例如 Jetty、Undertow 等。

11

Container


Container(也称为Catalina)是用来处理Connector传入的Servlet 连接请求的接口,是Tomcat 容器的父接口。它使用了责任链设计模式,由四个子容器组成:Engine、Host、Context、Wapper。这些容器之间是父子关系,Engine包含Host、Host包含Contest,Context包含Wrapper。

  • Engine(引擎):是Tomcat 实例的最顶层容器组件,负责处理所有的连接请求。一个Tomcat实例可以包含多个虚拟主机(Host),每个虚拟主机可以服务于不同的域名请求。Engine的实现通常是org.apache.catalina.core.StandardEngine。

  • Host(虚拟主机):代表一个虚拟主机,每个虚拟主机可以匹配一个或多个域名(Donain Name)。每个Host可以包含多个Context。一个Tomcat 实例可以包含多个Host,虚拟主机的数量并不一定是指一台服务器上的多个域名,而是可以理解为一个Tomcat 实例可以服务多个不同域名的请求虚拟主机的实现类通常是org.apache.catalina.core.StandardHost。

  • Context(上下文):对应于一个Web应用,包含了Web应用的配置信息,以及Servlet的映射关系。一个Context 可以包含多个Wrapper,每个Wrapper 对应一个Servelet。Context的实现类通常是org.apache.catalina.core.StandardContext。

  • Wrapper(包装器):负责管理Servlet的生命周期,包括装载,初始化、执行和回收资源。一个Wrapper可以对应多个Servlet,因为Wrapper可以处理多个URL模式,每个URL模式可以映射到不同的Servlet。Wrapper的实现类通常是org.apache.catalina.core.StandardWrapper。

Tomcat 的默认实现是 Catalina,它是Tomcat 的核心组件之一,主要负责处理Servlet的请求和管理Servlet 的生命周期。除了Catalina 之外,Tomcat还包含了一些其他核心组件,例如上面提到的连接器,用于处理网络连接和传输数据。

上面提到的四个实现类是Catalina 组件的一种实现,属于Tomcat的核心组件之一,这些实现类提供了标准的容器组件,用于组织和管理Web 应用的部署和执行。

从功能上区分我们可以把它们理解成这样一张图

  • Tomcat Server:相当于放置所有东西的桌子,它是整个 Tomcat 实例的顶层结构,类似于服务员服务的整个区域C

    • Tomcat Server 能容纳一个或多个服务(Service)

  • Tomcat Service:类似于叠在桌子上的一个个盘子,代表着独立的服务,就像不同种类的盘子。

    • 每个 Tomcat Service通常绑定到不同的IP地址和端口上,类似于不同种类的盘子放置在不同的地方等待服务。

    • 每个Tomcat Service 包含多个Connector,就像每个盘子上面可以放很多食物

  • Connector:就像服务员,负责接收客户的请求并将他们传递给Container进行处理。

    • 每个Connector 可以监听不同的网络端口,类似于不同的服务员负责不同的区域

  • Container:就像盘子上面放置的食物,负责处理客户端请求的具体业务逻辑。

    • 最主要的容器是Servlet容器,用于执行Servlet相关的任务,类似于主要的盘子上面放置主要的食物。

如果从层级区分我们可以将它们理解成这样一张图

虽然连接器(Connector)和容器(Container)是Tomcat中的重要组件,但他们并不是Tomcat的核心功能。他们是用来支持Tomcat核心功能的关键部分。

11

Tomcat 的核心功能


上面说的 Tomcat Server 、Tomcat Service、Connector、Container 是Tomcat 的4个核心组件,这4个组件是实现Tomcat核心功能的基础,Tomcat 的功能可以用下图表示:


把上面的各种知识进行串联:

为了便于对上面的Java Web 有一个整体之间关系的认识,在这里它们进行一个整体的串联,从整体的角度去看局部的功能和构造,这样能更清楚一些:

  • Tomcat Server 是整个系统的顶层组件,负责承载和运行Web 应用程序

  • Web Service 是Tomcat Server 的一个重要部分,包含了处理网络连接和传输数据的Connector以及负责管理和执行Web应用程序的Container

    • Connector 接收和处理来自客户端的HTTP请求,并将请求转发给Container中的相应组件。

    • Container 是Servlet容器,负责管理和执行Web应用程序的逻辑。它包括了Engine 和Host。

      • Engine 接收并处理来自Connector的HTTP 请求,根据请求的URL将其分给合适的虚拟主机Host

        • Servlet 是 Engine 中的组件,负责处理HTTP请求和响应,是整个系统的核心。

      • Host 代表了Tomcat 中的虚拟主机,每个虚拟主机可以包含多个Web应用程序。

  • Servlet API 包含了用于开发基于Java的Web应用程序的一组API,其中包括了过滤请求和响应的Filter、监听Web应用程序生命周期事件的Listener以及与其他Web服务器集成的Ada'pters。

    • Filter 用于过滤HTTP请求和响应,可以在请求到达Servlet之前或响应返回客户端之前修改或处理请求和响应。

    • Listener 用于监听Web应用程序的生命周期事件,例如应用程序的启动、停止、初始化和销毁等。

    • Adapter 用于与其他Web服务器集成,使得Tomcat能够与其他服务器协同工作,例如将Tomcat 作为后端服务器与Nginx 或 Apache 等前端服务器配合使用

    结语:

    感谢whoami师傅的投稿,非常感谢!

嗨嗨安全
提供网络安全资料与工具,分享攻防实战经验和思路。
 最新文章