当前位置: 首页 > news >正文

Tomcat Container的管道机制:责任链模式

  • Tomcat总计架构图中Pipeline和Vavle

  • 我们在上文Engine中有一块Pipline没有解释:

  • 为什么Tomcat要引入Pipline呢?它要解决什么问题呢?

下文将向你详细阐述。

知识准备

在弄清楚管道机制前,你需要一些基础知识和其它软件设计中的应用场景。

责任链模式

管道机制在设计模式上属于责任链模式,如果你不理解,请参看如下文章:

责任链模式(Chain of responsibility pattern): 通过责任链模式, 你可以为某个请求创建一个对象链. 每个对象依序检查此请求并对其进行处理或者将它传给链中的下一个对象。

FilterChain

在软件开发的常接触的责任链模式是FilterChain,它体现在很多软件设计中:

  • 比如Spring Security框架中

  • 比如HttpServletRequest处理的过滤器中

当一个request过来的时候,需要对这个request做一系列的加工,使用责任链模式可以使每个加工组件化,减少耦合。也可以使用在当一个request过来的时候,需要找到合适的加工方式。当一个加工方式不适合这个request的时候,传递到下一个加工方法,该加工方式再尝试对request加工。

网上找了图,这里我们后文将通过Tomcat请求处理向你阐述。

Pipline机制

为什么要有管道机制?

在一个比较复杂的大型系统中,如果一个对象或数据流需要进行繁杂的逻辑处理,我们可以选择在一个大的组件中直接处理这些繁杂的业务逻辑, 这个方式虽然达到目的,但扩展性和可重用性较差, 因为可能牵一发而动全身。更好的解决方案是采用管道机制,用一条管道把多个对象(阀门部件)连接起来,整体看起来就像若干个阀门嵌套在管道中一样,而处理逻辑放在阀门上

Vavle接口设计

理解它的设计,第一步就是阀门设计

java

public interface Valve { // 因为需要传递给下个Valve处理,所以有next public Valve getNext(); public void setNext(Valve valve); // 设计这个方法,便于执行周期任务,比如重新加载组件。此方法将在该容器的类加载上下文中调用。 public void backgroundProcess(); // 这个方法很容易理解,阀门中处理的执行方法,传入Request和Response进行处理 public void invoke(Request request, Response response) throws IOException, ServletException; // 此阀门是否支持Servlet 3+ 异步的请求 public boolean isAsyncSupported(); }

Pipline接口设计

由于Pipline是为容器设计的,所以它在设计时加入了一个Containerd接口, 就是为了制定当前Pipline所属的容器:

java

public interface Contained { Container getContainer(); void setContainer(Container container); }

我们接着看下Pipline接口设计

java

public interface Pipeline extends Contained { // 基础的处理阀 public Valve getBasic(); public void setBasic(Valve valve); // 对节点(阀门)增删查 public void addValve(Valve valve); public Valve[] getValves(); public void removeValve(Valve valve); // 获取第一个节点,遍历的起点,所以需要有这方法 public Valve getFirst(); // 是否所有节点(阀门)都支持处理Servlet3异步处理 public boolean isAsyncSupported(); // 找到所有不支持Servlet3异步处理的阀门 public void findNonAsyncValves(Set<String> result); }

BaseVavle设计

由于Valve也是组件,需要生命周期管理,所以实现LifecycleMBeanBase,同时集成Contained和Valve

java

public abstract class ValveBase extends LifecycleMBeanBase implements Contained, Valve { protected static final StringManager sm = StringManager.getManager(ValveBase.class); //------------------------------------------------------ Constructor public ValveBase() { this(false); } public ValveBase(boolean asyncSupported) { this.asyncSupported = asyncSupported; } //------------------------------------------------------ Instance Variables /** * Does this valve support Servlet 3+ async requests? */ protected boolean asyncSupported; /** * The Container whose pipeline this Valve is a component of. */ protected Container container = null; /** * Container log */ protected Log containerLog = null; /** * The next Valve in the pipeline this Valve is a component of. */ protected Valve next = null; //-------------------------------------------------------------- Properties /** * Return the Container with which this Valve is associated, if any. */ @Override public Container getContainer() { return container; } /** * Set the Container with which this Valve is associated, if any. * * @param container The new associated container */ @Override public void setContainer(Container container) { this.container = container; } @Override public boolean isAsyncSupported() { return asyncSupported; } public void setAsyncSupported(boolean asyncSupported) { this.asyncSupported = asyncSupported; } /** * Return the next Valve in this pipeline, or <code>null</code> if this * is the last Valve in the pipeline. */ @Override public Valve getNext() { return next; } /** * Set the Valve that follows this one in the pipeline it is part of. * * @param valve The new next valve */ @Override public void setNext(Valve valve) { this.next = valve; } //---------------------------------------------------------- Public Methods /** * Execute a periodic task, such as reloading, etc. This method will be * invoked inside the classloading context of this container. Unexpected * throwables will be caught and logged. */ @Override public void backgroundProcess() { // NOOP by default } @Override protected void initInternal() throws LifecycleException { super.initInternal(); containerLog = getContainer().getLogger(); } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { setState(LifecycleState.STARTING); } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); } /** * Return a String rendering of this object. */ @Override public String toString() { return ToStringUtil.toString(this); } // -------------------- JMX and Registration -------------------- @Override public String getObjectNameKeyProperties() { StringBuilder name = new StringBuilder("type=Valve"); Container container = getContainer(); name.append(container.getMBeanKeyProperties()); int seq = 0; // Pipeline may not be present in unit testing Pipeline p = container.getPipeline(); if (p != null) { for (Valve valve : p.getValves()) { // Skip null valves if (valve == null) { continue; } // Only compare valves in pipeline until we find this valve if (valve == this) { break; } if (valve.getClass() == this.getClass()) { // Duplicate valve earlier in pipeline // increment sequence number seq ++; } } } if (seq > 0) { name.append(",seq="); name.append(seq); } String className = this.getClass().getName(); int period = className.lastIndexOf('.'); if (period >= 0) { className = className.substring(period + 1); } name.append(",name="); name.append(className); return name.toString(); } @Override public String getDomainInternal() { Container c = getContainer(); if (c == null) { return null; } else { return c.getDomain(); } } }

StandardPipline实现

里面方法很简单,就直接贴代码了。它必然是继承LifecycleBase同时实现Pipline.

贴个图方面你理解

http://www.gsyq.cn/news/1592273.html

相关文章:

  • 金融绩效评估新范式:融合谱风险度量与文献计量思想的稳健排名体系
  • 做公开资料整理时,别忽略“失败记录”
  • 3步轻松获取百度网盘真实下载地址:告别限速的终极指南
  • 图论与交换代数的交汇:边理想正则性如何由匹配数决定
  • AI提示词进阶:BROKE框架
  • Ryujinx Nintendo Switch模拟器实战指南:跨平台游戏体验深度解析
  • 专门的 Socket 连接(`ProcessList.mWebViewZygote`)来管理它。
  • 2026多维横评|主流AI编程助手实战对比,国产化开发场景选型必看
  • 用python -m http.server快速搭建一个临时文件共享服务器
  • Windows MySQL5.5 搭建3307多实例从库(避坑完整版)
  • 【IDEA安装避坑指南】:20年Java架构师亲授Windows/macOS/Linux三端零错误安装全流程(附官方镜像校验码)
  • LeetDown:如何在10分钟内完成iOS设备安全降级的终极指南
  • 从“单点”到“全流程”——俊亿供应链借力 PEO 实现 X 国用工管理升级
  • 从VMware Workstation到vCenter——Web服务器跨平台迁移全路径(含Apache→Nginx无缝切换实录)
  • QKeyMapper:打破设备限制的Windows按键映射神器
  • 干货合集:盘点2026年最受喜爱的的AI论文平台
  • 【数据库系统原理】第28篇:多粒度封锁与意向锁:锁定层级的效率优化
  • 动图魔方技术拆解 07:ArkTS 实现 GIF LZW 编码与数据子块写入
  • 仅限内部技术团队流传的VMware MySQL部署Checklist(含vCPU分配公式、swap禁用策略、vmx参数优化表)
  • Poly Haven Assets Blender插件:原生资产浏览器深度集成架构解析
  • QuickRecorder完整指南:如何用这款免费macOS录屏工具提升你的工作效率
  • 终极MP4视频修复指南:5分钟拯救你的珍贵记忆
  • GitLab在VMware中性能暴跌90%?揭秘CPU争用、磁盘I/O瓶颈与内存泄漏三大隐形杀手
  • 产业观察:人形机器人从演示展示到实景落地的发展转变
  • 普通人怎么入局Ai,狂揽几W做副业?先学会用APi接入语言和画图模型(小白必看教程)
  • 别再手动配环境了!VMware Workstation Pro 17+Python 3.11+Poetry+Docker Desktop一体化部署流程(含SSH密钥自动注入技术)
  • 极值负依赖与联合互斥性:高维尾部风险建模新框架
  • AI 应用日志与监控系统构建实战
  • C风格字符串排序全解析【模板练习题】
  • 2026年AI大模型API代理网站全维度深度测评:主流服务商性能与成本全场景权威排名指南