责任链模式之Tomcat Filter应用

责任链模式之Tomcat Filter应用

责任链模式是一种对象的行为型模式。

其定义为:很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象处理此请求。发出这个请求的客户端并不知道链上哪个对象最终会处理这个请求,这使得系统可以在不影响客户端的情况下动态的重新组织和分配责任。

结构:

  1. 抽象处理者(Handler) 角色:定义出一个处理请求的接口。

  2. 具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。【持有对下家的引用】

优点:

  1. 降低耦合,

  2. 简化对象,

  3. 增强对象职责灵活性,

  4. 方便新增处理类。

缺点:

  1. 不能保证请求被接收,

  2. 系统性能受影响,容易造成循环调用。

例:dubbo里调用链/过滤链 的创建就是 责任链模式,tomcat filter也使用了责任链模式。

分析Tomcat Filter

核心逻辑入口:org.apache.catalina.core.StandardWrapperValve#invoke。

StandardWrapperValve 是 StandardWrapper的基础阀,其作用是加载Servlet,创建Filter过滤器,最终会调用Servlet的service方法。

//StandardWrapperValve类

@Override
public final void invoke(Request request, Response response)
    throws IOException, ServletException {
    省略代码......
    
    //分配一个Servlet实例来处理这个请求
    if (!unavailable) {
        servlet = wrapper.allocate();
    }
    
    //为此请求创建过滤器链
    ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
    
    //为此请求调用过滤器链,也会调用Servlet的service()方法
    filterChain.doFilter(request.getRequest(), response.getResponse());
    
    ......
}

分配Servlet实例

本文基于springboot 2.2.2.RELEASE 框架代码分析。

servlet = wrapper.allocate(); 此行代码是分配一个Servlet实例来处理请求。

由DispatcherServletAutoConfiguration自动配置类 向容器中注入 DispatcherServlet Bean。所有的请求由该类分发。

......
public class DispatcherServletAutoConfiguration {
   protected static class DispatcherServletConfiguration {

    ......
  @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
  public DispatcherServlet dispatcherServlet(HttpProperties httpProperties, WebMvcProperties webMvcProperties) {
    DispatcherServlet dispatcherServlet = new DispatcherServlet();
    dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
    dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
    dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
    dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
    dispatcherServlet.setEnableLoggingRequestDetails(httpProperties.isLogRequestDetails());
    return dispatcherServlet;
  }
}

创建过滤器链

ServletWebServerApplicationContextSpringApplicationContext容器的一个子类。

selfInitialize 方法会调用 getServletContextInitializerBeans 来获取ServletContextInitializer 实例对象集合。包含所有的ServletContextInitializer Bean对象(还适用于Servlet、Filter、EventListener Bean)。

ServletContextInitializer接口源码注释:

用于以编程方式配置 Servlet 3.0+ ServletContext的接口。

接口(并且不实现 WebApplicationInitializer} 将不会被SpringServletContainerInitializer 检测到,因此不会由 Servlet 容器自动引导。

此接口设计方式类似于 ServletContainerInitializer, 但其由 Spring 管理其生命周期而不是Servlet 容器。

addAdaptableBeans()

实例化并注册了所有实现Servlet、Filter及EventListener接口的类。所以此处就会加载Filter过滤器类(包括我们自定义的实现)。

//ServletContextInitializerBeans类

protected void addAdaptableBeans(ListableBeanFactory beanFactory) {
  MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory);
  addAsRegistrationBean(beanFactory, Servlet.class, new ServletRegistrationBeanAdapter(multipartConfig));
  addAsRegistrationBean(beanFactory, Filter.class, new FilterRegistrationBeanAdapter());
  for (Class<?> listenerType : ServletListenerRegistrationBean.getSupportedTypes()) {
   addAsRegistrationBean(beanFactory, EventListener.class, (Class<EventListener>) listenerType,
     new ServletListenerRegistrationBeanAdapter());
  }
 }

调用过滤器链

执行过滤器链,从ApplicationFilterConfig[] 数组中取出过滤器链执行,直到所有过滤器执行完毕。

private void internalDoFilter(ServletRequest request,
                              ServletResponse response)
    throws IOException, ServletException {

    if (pos < n) {
        ApplicationFilterConfig filterConfig = filters[pos++];
        Filter filter = filterConfig.getFilter();
        filter.doFilter(request, response, this);

        省略......
    }

    servlet.service(request, response);

    ......
}

最后会调用org.springframework.web.servlet.DispatcherServlet#doService。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值