Tomcat对Servlet规范的Filter及Listener实现

本文介绍了Tomcat如何处理Servlet请求,特别是Filter链的创建与调用。每个请求都会创建一个特定的Filter链,根据请求路径选择需要的Filter。Filter的作用域是整个Web应用,它们由Tomcat的StandardContext管理。当所有Filter执行完毕后,Servlet的service方法会被调用来处理业务逻辑。此外,还探讨了Filter和Listener的注册以及Listener如何监听和响应容器内的事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

StandardWrapperValve的invoke就三步:

  1. 创建Servlet实例

  2. 给当前请求创建一个Filter链

  3. 调用Filter链

[](()为何要给每个请求创建Filter链

每个请求的请求路径不同,而Filter都有相应路径映射,因此不是所有Filter都需要处理当前请求,要根据请求路径选择特定的一些Filter。

[](()为何没调用Servlet#service

Filter链的最后一个Filter会负责调用Servlet。

[](()Filter管理

=======================================================================

跟Servlet一样,Filter也可在web.xml配置。

但Filter的作用域是整个Web应用,因此Filter的实例维护在Context容器:Map里存的是filterDef(filter定义),而非filter类实例

Filter链存活期很短,它跟每个请求对应。一个新请求来了,就动态创建一个Filter链,请求处理完,Filter链就被回收。

public final class ApplicationFilterChain implements FilterChain {

// Filter链的Filter数组

private Appl 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 icationFilterConfig[] filters = new ApplicationFilterConfig[0];

// Filter链的当前的调用位置

private int pos = 0;

// Filter总数

private int n = 0;

// 每个Filter链最终要调用的Servlet

private Servlet servlet = null;

public void doFilter(ServletRequest req, ServletResponse res) {

internalDoFilter(request,response);

}

private void internalDoFilter(ServletRequest req,

ServletResponse res){

if (pos < n) {

ApplicationFilterConfig filterConfig = filters[pos++];

Filter filter = filterConfig.getFilter();

filter.doFilter(request, response, this);

return;

}

servlet.service(request, response);

}

internalDoFilter里会做个判断:

  • 若当前Filter位置 < Filter数组长度,即Filter还没调完,就从Filter数组取下一个Filter,调用其doFilter

  • 否则,说明已调用完所有Filter,该调用Servlet#service了。service方法是留给程序员实现业务逻辑的,比如CRUD

public void doFilter(ServletRequest request, ServletResponse response,

FilterChain chain){

//调用Filter的方法

chain.doFilter(request, response);

}

Filter#doFilter的FilterChain参数,就是Filter链。每个Filter#doFilter里必须调用Filter链的doFilter,而Filter链中保存当前Filter位置,会调用下一个Filter的doFilter方法,这样就能完成链式调用。

[](()对应的filter是怎么注册到Servlet的呢?

filter是注册到Servlet容器中,Tomcat的StandardContext类中维护了一个Filter列表,所谓注册就是把你写的filter类实例加到这个列表。

[](()Listener管理

=========================================================================

Listener可以监听容器内部发生的事件:

  • 生命状态的变化

比如Context容器启动和停止、Session的创建和销毁。

  • 属性变化

比如Context容器某个属性值变了、Session的某个属性值变了以及新的请求来了

[](()怎么添加监听器


在web.xml配置或注解添加,在监听器里实现业务逻辑。

Tomcat需读取配置文件,拿到监听器的类名,将它们实例化,并适时调用这些监听器方法。

Tomcat是通过Context容器来管理这些监听器的。Context容器将两类事件分开来管理,分别用不同的集合来存放不同类型事件的监听器:

//监听属性值变化的监听器

private List applicationEventListenersList = new CopyOnWriteArrayList<>();

//监听生命事件的监听器

private Object applicationLifecycleListenersObjects[] = new Object[0];

剩下的事情就是触发监听器了,比如在Context容器的启动方法里,就触发了所有的ServletContextListener:

// 1 拿到所有生命周期监听器

Object instances[] = getApplicationLifecycleListeners();

for (int i = 0; i < instances.length; i++) {

// 2 判断Listener的类型是否为ServletContextListener

if (!(instances[i] instanceof ServletContextListener))

continue;

// 3 触发Listener方法

ServletContextListener lr = (ServletContextListener) instances[i];

lr.contextInitialized(event);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值