源码分析:Tomcat - Filter - SpringBoot桥接原理

1. Filter - RequestContextHolder 上下文请求
2. Filter - SpringBoot桥接原理

前言

1
2
3
4
5
6
7
问1:Filter实现的方式有哪几种?

问2:为什么 Filter 会重复执行?

问3:怎么保证多个 Filter 的执行顺序?

问4:SpringBoot 如何集成的 Filter?

一. 前置工作:Spring上下文刷新,启动Tomcat,触发 ServletContextInitializerBeans

1
2
3
4
5
6
7
8
9
10
11
12
13
AbstractApplicationContext.refresh
ServletWebServerApplicationContext.onRefresh
ServletWebServerApplicationContext.createWebServer
// 收集 this::selfInitialize, 触发条件 TomcatStarter.onStartup
// this.webServer = factory.getWebServer(getSelfInitializer());
ServletWebServerApplicationContext.selfInitialize
// for循环触发迭代器 ServletContextInitializerBeans.iterator
// for (ServletContextInitializer beans : getServletContextInitializerBeans()) {// 触发方法
// beans.onStartup(servletContext);
// }
// 步骤2 创建 ServletContextInitializerBeans
ServletWebServerApplicationContext.getServletContextInitializerBeans
// new ServletContextInitializerBeans(getBeanFactory());

二. 桥接:ServletContextInitializerBeans 创建(省略不必要代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   private final MultiValueMap<Class<?>, ServletContextInitializer> initializers;
private List<ServletContextInitializer> sortedList;

public ServletContextInitializerBeans(ListableBeanFactory beanFactory, Class<? extends ServletContextInitializer>... initializerTypes) {
// [1] beanFactory 中收集 Filter 的包装类 FilterRegistrationBean --- 放入 initializers 集合中,用于下面排序
addAdaptableBeans(beanFactory);
// addAsRegistrationBean(beanFactory, Filter.class, new FilterRegistrationBeanAdapter());
// 实现类 ---> FilterRegistrationBean 默认拦截 "/*"
RegistrationBean registration = adapter.createRegistrationBean(beanName, bean, entries.size());
// 优先级:Ordered接口 -> @Order -> @Priority
// ===> AnnotationAwareOrderComparator#findOrder
int order = getOrder(bean);
registration.setOrder(order);

// [2] 排序、赋值给 sortedList
List<ServletContextInitializer> sortedInitializers = this.initializers.values()
.stream()
// Order 比较器
.flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE))
.collect(Collectors.toList());
this.sortedList = Collections.unmodifiableList(sortedInitializers);
}

// [3] 迭代器,用于第一步中的 for循环
public Iterator<ServletContextInitializer> iterator() {
return this.sortedList.iterator();
}

三. 最终实现:Filter 添加到 ServletContext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
   // [1] 继承关系、与 成员变量
FilterRegistrationBean<T extends Filter> extends AbstractFilterRegistrationBean<T>
AbstractFilterRegistrationBean extends DynamicRegistrationBean
DynamicRegistrationBean extends RegistrationBean
RegistrationBean implements ServletContextInitializer, Ordered
private T filter;

// [2] 被第一步 for循环来触发 --- 最终添加到 ServletContext
RegistrationBean.onStartup
// register(description, servletContext);
DynamicRegistrationBean.register
// D registration = addRegistration(description, servletContext);
AbstractFilterRegistrationBean.addRegistration
// Filter filter = getFilter();
// return servletContext.addFilter(getOrDeduceName(filter), filter);
// ApplicationContextFacade.addFilter

四. 创建 Filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// @Priority(333)
@Order(222)
@Component
public class AuthFilter implements Filter/*, Ordered*/ {

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println(123);

Map<String, Filter> beansOfType = SpringUtil.getBeansOfType(Filter.class);
// beansOfType = {LinkedHashMap@15247} size = 7
// "authFilter" -> {AuthFilter@15246}
// "CORSFilter" -> {CORSFilter@15047}
// "ipFilter" -> {IpFilter@15227}
// "tokenFilter" -> {TokenFilter@15067}
// "requestContextFilter" -> {OrderedRequestContextFilter@15051}
// "formContentFilter" -> {OrderedFormContentFilter@15052}
// "characterEncodingFilter" -> {OrderedCharacterEncodingFilter@15053}
}

// @Override
// public int getOrder() {
// return 111;
// }
}

五. 实现原理:@ServletComponentScan + @WebFilter(省略不必要代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// [1] @ServletComponentScan 本质是 @Import
// 这个使用同 @SpringBootApplication 的 @EnableAutoConfiguration 的 @Import(AutoConfigurationImportSelector.class)
@Import(ServletComponentScanRegistrar.class)
public @interface ServletComponentScan {


// [2] 注入 BeanFactoryPostProcessor
// 说明一句:BeanFactoryPostProcessor 是对 BeanDefinition加工处理
// 说明一句:BeanPostProcessor 是对 Bean加工处理
class ServletComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
// 2.1
addPostProcessor(registry, packagesToScan);
}

private void addPostProcessor(BeanDefinitionRegistry registry, Set<String> packagesToScan) {
// 2.2
ServletComponentRegisteringPostProcessorBeanDefinition definition = new ServletComponentRegisteringPostProcessorBeanDefinition( packagesToScan);
registry.registerBeanDefinition(BEAN_NAME, definition);
}

static final class ServletComponentRegisteringPostProcessorBeanDefinition extends GenericBeanDefinition {
@Override
public Supplier<?> getInstanceSupplier() {
// 2.3
return () -> new ServletComponentRegisteringPostProcessor(this.packageNames);
}
}
}


// [3] 扫描,如果符合走 WebFilterHandler.handle
class ServletComponentRegisteringPostProcessor implements BeanFactoryPostProcessor, ApplicationContextAware {
private static final List<ServletComponentHandler> HANDLERS;

static {
List<ServletComponentHandler> servletComponentHandlers = new ArrayList<>();
servletComponentHandlers.add(new WebServletHandler());
servletComponentHandlers.add(new WebFilterHandler());// 逮到
servletComponentHandlers.add(new WebListenerHandler());
HANDLERS = Collections.unmodifiableList(servletComponentHandlers);
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
ClassPathScanningCandidateComponentProvider componentProvider = createComponentProvider();
for (String packageToScan : this.packagesToScan) {
scanPackage(componentProvider, packageToScan);
}
}

private void scanPackage(ClassPathScanningCandidateComponentProvider componentProvider, String packageToScan) {
for (BeanDefinition candidate : componentProvider.findCandidateComponents(packageToScan)) {
if (candidate instanceof AnnotatedBeanDefinition) {
for (ServletComponentHandler handler : HANDLERS) {
// 触发 WebFilterHandler.doHandle
handler.handle(((AnnotatedBeanDefinition) candidate), (BeanDefinitionRegistry) this.applicationContext);
}
}
}
}
}


// [4] 这里注入 Bean定义,所以 @ServletComponentScan + @WebFilter 这种方式的本质还是成为 Spring Bean,然后再被上述的 一 二 三步 处理到 Tomcat链路,
// 重点注意:导致是否重复注入 Filter,就是 Bean 的名称, @WebFilter.filterName不存在,就使用 类的全限定类名 做为Bean名称,例如:"com.taopanfeng.config.AuthFilter"
// @ServletComponentScan + @WebFilter 注入一次, @Component 又注入了一次, 导致每次请求就会走两次 Filter
class WebFilterHandler extends ServletComponentHandler {
WebFilterHandler() {
super(WebFilter.class);
}

@Override
public void doHandle(Map<String, Object> attributes, AnnotatedBeanDefinition beanDefinition, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterRegistrationBean.class);
builder.addPropertyValue("asyncSupported", attributes.get("asyncSupported"));
builder.addPropertyValue("dispatcherTypes", extractDispatcherTypes(attributes));
builder.addPropertyValue("filter", beanDefinition);
builder.addPropertyValue("initParameters", extractInitParameters(attributes));
String name = determineName(attributes, beanDefinition);
builder.addPropertyValue("name", name);// 这个是直接影响到 重复添加 @Filter 的关键
builder.addPropertyValue("servletNames", attributes.get("servletNames"));
builder.addPropertyValue("urlPatterns", extractUrlPatterns(attributes));
registry.registerBeanDefinition(name, builder.getBeanDefinition());
}

private String determineName(Map<String, Object> attributes, BeanDefinition beanDefinition) {
return (String) (StringUtils.hasText((String) attributes.get("filterName")) ? attributes.get("filterName")
: beanDefinition.getBeanClassName());// 类的全限定类名
}
}