從零手寫實現 tomcat-11-filter 過濾器

創作緣由

平時使用 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);@Overridepublic 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 {//... 省略基礎屬性@Overridepublic void register(String url, Filter filter) {logger.info("[MiniCat] register Filter, url={}, Filter={}", url, filter.getClass().getName());filterMap.put(url, filter);}@Overridepublic Filter getFilter(String url) {return filterMap.get(url);}@Overridepublic 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. 處理 filterfinal 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();//beforeList<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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/12912.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/12912.shtml
英文地址,請注明出處:http://en.pswp.cn/web/12912.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

基于Springboot的學生心理壓力咨詢評判(有報告)。Javaee項目,springboot項目。

演示視頻&#xff1a; 基于Springboot的學生心理壓力咨詢評判&#xff08;有報告&#xff09;。Javaee項目&#xff0c;springboot項目。 項目介紹&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三層體系…

Yalmip使用教程(8)-常見報錯及調試方法

博客中所有內容均來源于自己學習過程中積累的經驗以及對yalmip官方文檔的翻譯&#xff1a;https://yalmip.github.io/tutorials/ 這篇博客將詳細介紹使用yalmip工具箱編程過程中的常見錯誤和相應的解決辦法。 1.optimize的輸出參數 眾所周知&#xff0c;optimize是yalmip用來求…

5.7日學習記錄及相關問題解答

1. 閱讀文章 復習 JAVA基礎——接口&#xff08;全網最詳細教程&#xff09; Java之對象的多態性&#xff08;使用生活中通俗的例子講解&#xff09; 新學 JavaWeb——Servlet&#xff08;全網最詳細教程包括Servlet源碼分析&#xff09; 有用 創建Dynamic Web Project工程&…

PS濾鏡插件Camera Raw 15.4升級,開啟智能修圖

前段時間Adobe 更新了photoshop 的智能AI填充功能&#xff0c;深受很多設計師朋友的喜愛。Camera Raw作為PS的一個濾鏡插件對RAW圖片的處理上面有一定的優勢&#xff0c;Camera Raw 15.4升級了&#xff0c;開啟智能修圖木事&#xff0c;一起來看看吧&#xff01; Camera Raw濾鏡…

【2024華為HCIP831 | 高級網絡工程師之路】刷題日記(18)

個人名片&#xff1a;&#x1faaa; &#x1f43c;作者簡介&#xff1a;一名大三在校生&#xff0c;喜歡AI編程&#x1f38b; &#x1f43b;???個人主頁&#x1f947;&#xff1a;落798. &#x1f43c;個人WeChat&#xff1a;hmmwx53 &#x1f54a;?系列專欄&#xff1a;&a…

ClassificationPrimitive 內部原理

ClassificationPrimitive 內部原理 發明 ClassificationPrimitive的真是個天才。其原理是利用 webgl 的模板緩沖區實現。 渲染兩次, 首先是繪制模板, 然后繪制真正的內容。 示意圖: function createClass() {const { program, uniforms } WebGLProgram.buildPrograms(gl, …

代碼隨想錄算法訓練營第36期DAY22

DAY22 654最大二叉樹 自己做的時候忽略了&#xff1a;nums.length>1的題給條件。所以每次遞歸都要判斷是否size()>1&#xff0c;不要空的。 /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *rig…

牛客網刷題 | BC84 牛牛學數列2

目前主要分為三個專欄&#xff0c;后續還會添加&#xff1a; 專欄如下&#xff1a; C語言刷題解析 C語言系列文章 我的成長經歷 感謝閱讀&#xff01; 初來乍到&#xff0c;如有錯誤請指出&#xff0c;感謝&#xff01; 描述 這次牛牛又換了個數…

sql中的exists和in的區別

在SQL中&#xff0c;EXISTS 和 IN 都用于子查詢&#xff0c;但它們的用法和目的有所不同。 ### EXISTS EXISTS 是一個邏輯運算符&#xff0c;用于檢查子查詢是否返回任何行。如果子查詢返回至少一行&#xff0c;那么 EXISTS 子句的結果為 TRUE&#xff1b;否則&#xff0c;結果…

一個用Kotlin編寫簡易的串行任務調度器

引言 由于項目中有處理大量后臺任務并且串行執行的需求&#xff0c;特意寫了一個簡易的任務調度器&#xff0c;方便監控每個任務執行和異常情況&#xff0c;任務之間互不影響。正如上所述&#xff0c;Kotlin中的TaskScheduler類提供了一個強大的解決方案&#xff0c;用于使用S…

「AIGC」Python實現tokens算法

本文主要介紹通過python實現tokens統計,避免重復調用openai等官方api,開源節流。 一、設計思路 初始化tokenizer使用tokenizer將文本轉換為tokens計算token的數量二、業務場景 2.1 首次加載依賴 2.2 執行業務邏輯 三、核心代碼 from transformers import AutoTokenizer imp…

React: memo

React.memo 允許你的組件在 props 沒有改變的情況下跳過重新渲染。 const MemoizedComponent memo(SomeComponent, arePropsEqual?)React 通常在其父組件重新渲染時重新渲染一個組件。你可以使用 memo 創建一個組件&#xff0c;當它的父組件重新渲染時&#xff0c;只要它的新…

centos7服務器采用局域網內筆記本代理上網

一、背景 某臺服務器操作系統是centos 7&#xff0c;不能上網。我想在上面裝個ftp軟件&#xff1a;vsftpd。 二、思路 要安裝這個軟件&#xff0c;有2種方案 1&#xff09;設置該臺centos7可以上網 2&#xff09;離線安裝vsftpd 鑒于各種依賴&#xff0c;萬一因為依賴不全或…

《海峽科技與產業》是什么級別的期刊?是正規期刊嗎?能評職稱嗎?

問題解答 問&#xff1a;《海峽科技與產業》期刊是什么級別&#xff1f; 答&#xff1a;國家級 主管單位&#xff1a;中華人民共和國科學技術部 主辦單位&#xff1a;科技部海峽兩岸科學技術交流中心 問&#xff1a;《海峽科技與產業》影響因子&#xff1f; 答&#xff1a;…

相位;傅里葉變換和傅里葉級數是什么;歐拉公式是什么,和傅里葉關系;

目錄 相位 傅里葉變換公式使用舉例 實際案例 傅里葉變換和傅里葉級數是什么

隨筆:棋友們

我是在小學二年級學會中國象棋的&#xff0c;準確說&#xff0c;是學會象棋的下棋規則的&#xff0c;師傅是二舅。我最早的對手就是同學波仔。波仔比我略早學會象棋&#xff0c;總用連珠炮欺負我&#xff0c;開局幾步棋就把我將死。我不知道怎么破解。輪到我先走時&#xff0c;…

扭虧為盈的賽力斯,真正進入穩態了嗎?

“72小時內大定破1萬臺”。5月15日&#xff0c;問界新M5開啟全國大規模交付&#xff0c;從當前取得的成績來看&#xff0c;賽力斯的“富貴”似乎還將延續。 其實&#xff0c;此前基于問界新M7等車型的爆火&#xff0c;賽力斯已經找到了創收軌道。財報顯示&#xff0c;2024年一…

alist網盤自動同步

alist網盤自動同步 alist可以設置目錄定時轉存到各個網盤&#xff0c;做到夸網盤&#xff0c;多備份的效果可以將自己掛載的alist 下的各個目錄相互間進行同步&#xff0c;原理是采用alist原始api調用執行同步原理1.匹配文件名稱是否相同,2.文件大小是否相同&#xff0c;相同會…

一文詳細解析Google編碼規范工具cpplint的下載安裝與使用

目錄 一、什么是cpplint 二、cpplint能實現的功能 三、cpplint的下載與使用 1、配置python環境 2、安裝cpplint 四、cpplint常用命令講解 1、常用命令查看 2、常用命令詳解 3、命令使用方式 五、 cpplint的實用技巧 1、集成cpplint 1.1、修改調用接口. 1.2、直接把…

數據結構(C):樹的概念和二叉樹初見

目錄 &#x1f37a;0.前言 1.樹概念及結構 2.認識一棵樹 3.樹的表示 3.1樹在實際中的運用&#xff08;表示文件系統的目錄樹結構&#xff09; 4.二叉樹 4.1特殊的二叉樹 4.2二叉樹的性質 &#x1f48e;5.結束語 &#x1f37a;0.前言 言C之言&#xff0c;聊C之識&…