责任链模式之Tomcat Filter应用
责任链模式是一种对象的行为型模式。
其定义为:很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象处理此请求。发出这个请求的客户端并不知道链上哪个对象最终会处理这个请求,这使得系统可以在不影响客户端的情况下动态的重新组织和分配责任。
结构:
-
抽象处理者(Handler) 角色:定义出一个处理请求的接口。
-
具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。【持有对下家的引用】
优点:
-
降低耦合,
-
简化对象,
-
增强对象职责灵活性,
-
方便新增处理类。
缺点:
-
不能保证请求被接收,
-
系统性能受影响,容易造成循环调用。
例: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;
}
}
创建过滤器链
ServletWebServerApplicationContext
是 Spring
的 ApplicationContext
容器的一个子类。
其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。