首页 > 其他分享 >从零手写实现 tomcat-11-filter 过滤器

从零手写实现 tomcat-11-filter 过滤器

时间:2024-05-12 11:19:33浏览次数:26  
标签:11 Filter 请求 tomcat filter import 手写

创作缘由

平时使用 tomcat 等 web 服务器不可谓不多,但是一直一知半解。

于是想着自己实现一个简单版本,学习一下 tomcat 的精髓。

系列教程

从零手写实现 apache Tomcat-01-入门介绍

从零手写实现 apache Tomcat-02-web.xml 入门详细介绍

从零手写实现 tomcat-03-基本的 socket 实现

从零手写实现 tomcat-04-请求和响应的抽象

从零手写实现 tomcat-05-servlet 处理支持

从零手写实现 tomcat-06-servlet bio/thread/nio/netty 池化处理

从零手写实现 tomcat-07-war 如何解析处理三方的 war 包?

从零手写实现 tomcat-08-tomcat 如何与 springboot 集成?

从零手写实现 tomcat-09-servlet 处理类

从零手写实现 tomcat-10-static resource 静态资源文件

从零手写实现 tomcat-11-filter 过滤器

从零手写实现 tomcat-12-listener 监听器

前言

还记得我们最初 web.xml 中的 filter 吗?

<?xml version="1.0" encoding="UTF-8" ?>
<web-app>
    <!-- Filter 配置 -->
    <filter>
        <filter-name>LoggingFilter</filter-name>
        <filter-class>com.github.houbb.minicat.support.filter.MyMiniCatLoggingHttpFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>LoggingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

他的作用是什么?我们又该如何解析实现呢?

filter 是什么?

在Tomcat中,Filter可以被看作是一个网络请求的“安检员”。

就像你进火车站或机场前要经过安检一样,网络请求在到达它最终的目的地(比如一个Servlet)之前,也可以先经过一些Filter的处理。

Filter主要有以下几个作用:

过滤请求:Filter可以检查进入的请求,看看它是否满足某些条件。如果不满足,Filter可以拒绝这个请求,就像安检员发现你携带了违禁品,就不让你进站一样。

修改请求:除了检查请求,Filter还可以修改请求。比如,它可以添加一些请求头,或者改变请求参数等。

过滤响应:同样,Filter也可以检查服务器的响应,看看它是否满足某些条件。如果不满足,Filter可以修改这个响应。

修改响应:除了检查响应,Filter也可以修改响应的内容。比如,它可以添加一些额外的信息,或者改变响应的格式等。

tomcat 如何处理 filter 的?

客户端(比如浏览器)发送一个请求到Tomcat。

Tomcat的连接器(Connector)接收到这个请求。

请求首先经过所有的Filter链。每个Filter都有机会检查和修改这个请求。

一旦所有的Filter都处理完毕,请求就到达它的目标Servlet。

Servlet处理请求,并生成一个响应。

响应再次经过Filter链,每个Filter都有机会检查和修改这个响应。

最后,响应被发送回客户端。

自己实现

接口定义

这里就不定义了,直接复用 servlet 的标准 api

接口实现

简单的实现

package com.github.houbb.minicat.support.filter;

import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpFilter;
import java.io.IOException;

/**
 * 
 * @since 0.6.0
 */
public class MyMiniCatLoggingHttpFilter extends HttpFilter {

    private static final Log logger = LogFactory.getLog(MyMiniCatLoggingHttpFilter.class);

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        logger.info("[MiniCat] MyMiniCatLoggingHttpFilter#doFilter req={}, resp={}", req, res);

        super.doFilter(req, res, chain);
    }

}

应用启动解析

DefaultFilterManager

定义一个 filter 的管理类

package com.github.houbb.minicat.support.filter.manager;

import com.github.houbb.heaven.util.lang.StringUtil;
import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;
import com.github.houbb.minicat.exception.MiniCatException;
import com.github.houbb.minicat.support.servlet.manager.DefaultServletManager;

import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * filter 管理
 *
 * @since 0.6.0
 * @author 老马啸西风
 */
public class DefaultFilterManager implements IFilterManager {

    //... 省略基础属性

    @Override
    public void register(String url, Filter filter) {
        logger.info("[MiniCat] register Filter, url={}, Filter={}", url, filter.getClass().getName());

        filterMap.put(url, filter);
    }

    @Override
    public Filter getFilter(String url) {
        return filterMap.get(url);
    }

    @Override
    public List<Filter> getMatchFilters(String url) {
        List<Filter> resultList = new ArrayList<>();

        for(Map.Entry<String, Filter> entry : filterMap.entrySet()) {
            String urlPattern = entry.getKey();
            if(url.matches(urlPattern)) {
                resultList.add(entry.getValue());
            }
        }

        return resultList;
    }


}

register 的时机

以本地的 web.xml 解析为例

/**
 * 处理 web 文件
 */
protected void processWebXml() {
    try {
        SAXReader reader = new SAXReader();
        Document document = reader.read(webXmlFile);
        Element root = document.getRootElement();

        // ...

        //2. 处理 filter
        final IFilterManager filterManager = this.miniCatContextConfig.getFilterManager();
        processWebFilter(root, filterManager);

        // ...
    } catch (Exception e) {
        throw new MiniCatException(e);
    }
}

解析对应的 web.xml 标签内容,注册对应信息:

protected void handleFilterConfigMap(Map<String, String> filterClassNameMap, Map<String, String> urlPatternMap, final IFilterManager filterManager) {
    try {
        for (Map.Entry<String, String> urlPatternEntry : urlPatternMap.entrySet()) {
            String filterName = urlPatternEntry.getKey();
            String urlPattern = urlPatternEntry.getValue();
            String className = filterClassNameMap.get(filterName);
            if (StringUtil.isEmpty(className)) {
                throw new MiniCatException("className not found for filterName: " + filterName);
            }
            Class servletClazz = Class.forName(className);
            Filter httpServlet = (Filter) servletClazz.newInstance();
            // 构建
            String fullUrlPattern = buildFullUrlPattern(urlPattern);
            filterManager.register(fullUrlPattern, httpServlet);
        }
    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
        throw new MiniCatException(e);
    }
}

这样就可以后面调用了。

调用的时机

我们什么时候调用呢?

当然是一个请求地址过来了,看是否有匹配的 filter,然后进行处理。

@Override
public void dispatch(final IMiniCatRequest request,
                     final IMiniCatResponse response,
                     final MiniCatContextConfig config) {
    final IServletManager servletManager = config.getServletManager();
    // 判断文件是否存在
    String requestUrl = request.getUrl();
    //before
    List<Filter> filterList = config.getFilterManager().getMatchFilters(requestUrl);
    // 获取请求分发
    final IRequestDispatcher requestDispatcher = getRequestDispatcher(requestUrl);
    // 请求前
    filterList.forEach(filter -> {
        try {
            filter.doFilter(request, response, null);
        } catch (IOException | ServletException e) {
            throw new RuntimeException(e);
        }
    });
    // 正式分发
    requestDispatcher.dispatch(request, response, config);
}

这样,一个基础的 filter 功能就实现了。

开源地址

 /\_/\  
( o.o ) 
 > ^ <

mini-cat 是简易版本的 tomcat 实现。别称【嗅虎】(心有猛虎,轻嗅蔷薇。)

开源地址:https://github.com/houbb/minicat

标签:11,Filter,请求,tomcat,filter,import,手写
From: https://www.cnblogs.com/houbbBlogs/p/18187603

相关文章

  • Windows Server 2025 简体中文版下载 (Inside Preview, updated May 2024) - 下一代 W
    WindowsServer2025简体中文版下载(InsidePreview,updatedMay2024)-下一代Windows11ServerWindowsServer2025正式版发布在即请访问原文链接:WindowsServer2025简体中文版下载(InsidePreview,updatedMay2024)-下一代Windows11Server,查看最新版。原创......
  • 5.11
    jetpackcompose搭建地铁系统页面@OptIn(ExperimentalMaterial3Api::class)@ComposablefunHomeScreen(viewModel:HomeViewModel=viewModel(factory=AppViewModelProvider.Factory)){SideEffect{viewModel.findMetroSystems()}valtabT......
  • 微软官方确认!Win11 24H2将默认启用BitLocker磁盘加密
    微软近日向国外媒体确认,Windows1124H2版本将在系统装机时默认启用BitLocker磁盘加密。微软表示,已经对安装程序进行了调整,移除了之前与ModernStandby/HSTI验证和不受信任的DMA端口检查相关的步骤,用户在重新安装Windows11过程中,将会默认启用设备加密。尽管这一默认加密策略近......
  • 2024-05-11 react-native 相关面试题
     ReactNative是什么?ReactNative是Facebook开源的一个使用JavaScript和React编写原生应用的框架。它允许开发者使用JavaScript和React编写跨平台的移动应用,这些应用可以运行在iOS和Android平台上。ReactNative有哪些优点?跨平台:一套代码可以开发出跨平台的app,减少了人......
  • React、Vue我全都要!React Hook 实现 Vue 的11个基本功能
    注:转自https://zhuanlan.zhihu.com/p/647975794,非商用,仅用于自我学习1、JSX和template在Vue2中是使用template的,这点使用Vue的同学们都知道,而在React中使用的是JSX,JSX是一个看起来很像XML的JavaScript语法扩展。它有以下优点:JSX执行更快,因为它在编译为JavaScript......
  • python教程11-面向对象
    python的面向对象和java有一些不一样:(java中,只有在类中定义的变量实例才能用,但是python更加灵活)类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实......
  • 【坑】严重性 代码 说明 项目 文件 行 禁止显示状态 错误 NETSDK1141 无法解析位于 E:
    错误严重性代码说明项目文件行禁止显示状态错误NETSDK1141无法解析位于E:\firefox\WPF-Samples-main\WPF-Samples-main\global.json的global.json中指定的.NETSDK版本。DragDropObjectsC:\ProgramFiles\dotnet\sdk\8.0.202\Sdks\Microsoft.NET.Sdk\targets\M......
  • 0511分析类
    1逻辑推理题分为推理类和分析类(一般都从题干中提到最多的信息入手)2.分析类分文真假分析和范畴分析3.真假分析:方法1:找矛盾3种情况1.A和非A(A且B与非A或非B)(A或B和非A且非B)2.A=》B和A且非B3.所有和有些不有些和所有不可能和必然不方法2:假设某人为真,判断其他会不会也为......
  • 从零手写实现 tomcat-09-servlet 处理类
    创作缘由平时使用tomcat等web服务器不可谓不多,但是一直一知半解。于是想着自己实现一个简单版本,学习一下tomcat的精髓。系列教程从零手写实现apacheTomcat-01-入门介绍从零手写实现apacheTomcat-02-web.xml入门详细介绍从零手写实现tomcat-03-基本的socket实......
  • m1_day11
    课程内容:StringBuffer类常见的方法面向对象的高阶特征访问权限修饰符static修饰符final修饰符abstract修饰符单例模式StringBuffer类常见的方法:*append(String):往字符串里面追加连接reverse():翻转字符串insert(int,char):往指定下标处插入......