springboot 2.1.3.RELEASE添加filter,servlet源码学习
Servlet规范中,通过ServeltContext来注册Filter、Servlet,这里分析Filter,Servlet是相同逻辑
springboot2.0中,我们通过
FilterRegistrationBean将指定得filter来实现ServeltContext注册filter
FilterRegistrationBean的实例化过程 public FilterRegistrationBean(T filter, ServletRegistrationBean... servletRegistrationBeans) { super(servletRegistrationBeans); Assert.notNull(filter, "Filter must not be null"); this.filter = filter; } super的实例化 AbstractFilterRegistrationBean(ServletRegistrationBean... servletRegistrationBeans) { Assert.notNull(servletRegistrationBeans, "ServletRegistrationBeans must not be null"); Collections.addAll(this.servletRegistrationBeans, servletRegistrationBeans); }
可知FilterRegistrationBean得实例化过程就是将Filter保存到servletRegistrationBeans(一个set)中
再分析FilterRegistrationBean类
FilterRegistrationBean的父类是一个ServletContextInitializer,他有一个方法onStartup(ServletContext servletContext)
其结果最终会调用
servletContext.addFilter(this.getOrDeduceName(filter), filter)
现在看看ServletContextInitializer.onStartup的调用地方
springboot启动 new SpringApplication(XXApplication.class).run(XXApplication.class,args) 调用 refreshContext(context); -> refresh(context); -> ((AbstractApplicationContext) applicationContext).refresh(); -> ServletWebServerApplicationContext.onRefresh(); -> createWebServer(); WebServer webServer = this.webServer; ServletContext servletContext = getServletContext(); if (webServer == null && servletContext == null) { ServletWebServerFactory factory = getWebServerFactory(); this.webServer = factory.getWebServer(getSelfInitializer()); }
再分析getSelfInitializer方法
prepareWebApplicationContext(servletContext); registerApplicationScope(servletContext); WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(),servletContext); for (ServletContextInitializer beans :getServletContextInitializerBeans()) {
//调用ServletContextInitializer的onStartup方法
beans.onStartup(servletContext);
}
-> getServletContextInitializerBeans()
-> new ServletContextInitializerBeans(getBeanFactory()) -> addAdaptableBeans(beanFactory)
addAdaptableBeans(ListableBeanFactory beanFactory) 代码如下: MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory); //将servlet类的bean包装为ServletRegistrationBean addAsRegistrationBean(beanFactory, Servlet.class,new ServletRegistrationBeanAdapter(multipartConfig)); //将Filter的bean包装为FilterRegistrationBean addAsRegistrationBean(beanFactory, Filter.class,new FilterRegistrationBeanAdapter()); for (Class<?> listenerType : ServletListenerRegistrationBean.getSupportedTypes()) {
addAsRegistrationBean(beanFactory, EventListener.class,(Class<EventListener>) listenerType,new ServletListenerRegistrationBeanAdapter()); }
这里提一下,如果Servlet的bean实例名为dispatcherServlet,且该实例在seen集合中(seen集合为自定义配置的实例,通过ServletContextInitializerBeans.addServletContextInitializerBean入口可以查看源码),则设置默认值为 /
String url = (totalNumberOfSourceBeans != 1) ? "/" + name + "/" : "/"; if (name.equals(DISPATCHER_SERVLET_NAME)) { url = "/"; // always map the main dispatcherServlet to "/" } ServletRegistrationBean<Servlet> bean = new ServletRegistrationBean<>(source,url);
bean.setName(name); bean.setMultipartConfig(this.multipartConfig); return bean;
总结:springboot启动时,会将所有的 FilterRegistrationBean、ServletRegistrationBean以及被spring管理的Servlet和Filter的实例,通过ServletContext注册Servlet以及Filter
如果不希望filter自动注册,可以通过以下方式:
@Bean public FilterRegistrationBean registration(@Qualifier("loginFilter") LoginFilter loginFilter) { FilterRegistrationBean registration = new FilterRegistrationBean(loginFilter); registration.setEnabled(false); return registration; }