执行顺序

tomcat—>connect—>Filter::doFilter—>Servlet::doService

为何 Filter 可以监控 servlet 执行请求时间

ApplicationFilterChain 调用filter 实现, filter 实现复又调用 ApplicationFilterChain,执行完 service 后,又会到 filter 实现的调用栈。

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

    // Call the next filter if there is one
    if (pos < n) {
        ApplicationFilterConfig filterConfig = filters[pos++];
        Filter filter = filterConfig.getFilter();
        filter.doFilter(request, response, this);
        return;
    }

    // We fell off the end of the chain -- call the servlet instance
    servlet.service(request, response);
}

原理

org.springframework.boot.web.servlet包

TomcatStarter(ServletContainerInitializer)—>

ServletWebServerApplicationContext—>ServletContextInitializerBeans#addAdaptableBeans

public ServletContextInitializerBeans(ListableBeanFactory beanFactory) {
	this.initializers = new LinkedMultiValueMap<>();
	addServletContextInitializerBeans(beanFactory);
	addAdaptableBeans(beanFactory);
	List<ServletContextInitializer> sortedInitializers = this.initializers.values()
			.stream()
			.flatMap((value) -> value.stream()
					.sorted(AnnotationAwareOrderComparator.INSTANCE))
			.collect(Collectors.toList());
	this.sortedList = Collections.unmodifiableList(sortedInitializers);
}
private 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());
	}
}

直接实现 javax.servlet.Filter


@Component
@Slf4j
public class AppDemoFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("-----------application filter init----------------");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("--------pre filter----------");
        chain.doFilter(request,response);
        log.info("--------post filter----------");
    }

    @Override
    public void destroy() {
        log.info("-----------application filter destroy----------------");
    }
}

包装成 FilterRegistrationBean 可以有更多控制权


@Bean
public FilterRegistrationBean<WebMvcMetricsFilter> webMvcMetricsFilter(
		MeterRegistry registry, MetricsProperties properties,
		WebMvcTagsProvider tagsProvider, WebApplicationContext context) {
	Server serverProperties = properties.getWeb().getServer();
	WebMvcMetricsFilter filter = new WebMvcMetricsFilter(context, registry,
			tagsProvider, serverProperties.getRequestsMetricName(),
			serverProperties.isAutoTimeRequests());
	FilterRegistrationBean<WebMvcMetricsFilter> registration = new FilterRegistrationBean<>(
			filter);
	registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
	registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);
	return registration;
}