由於springboot基於servlet3.0+,內嵌tomcat容器 因此無法像之前一樣通過web.xml中配置Filter,本文基於springboot1.5.6
第一種
@WebFilter(filterName = "myFilter",urlPatterns = "/*") public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { } @Override public void destroy() { } } @SpringBootApplication @EnableAutoConfiguration @EnableWebMvc @ServletComponentScan(basePackages = "com.fanyin.eghm") public class EghmApplication { public static void main(String[] args) { SpringApplication.run(EghmApplication.class, args); } }
@ServletComponentScan
所掃描的包路徑必須包含該Filter
第二種
@Configuration public class FilterConfig { @Bean public FilterRegistrationBean filterRegistrationBean(){ FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new MyFilter2()); bean.addUrlPatterns("/*"); return bean; } }
第三種
@Bean("proxyFilter") public Filter filter (){ return new Filter() { @Override public void init(javax.servlet.FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { } @Override public void destroy() { } }; } @Bean public DelegatingFilterProxyRegistrationBean delegatingFilterProxyRegistrationBean(){ DelegatingFilterProxyRegistrationBean bean = new DelegatingFilterProxyRegistrationBean("proxyFilter"); bean.addUrlPatterns("/*"); return bean; }
方法四
@Bean("myFilter") public Filter filter (){ return new Filter() { @Override public void init(javax.servlet.FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { } @Override public void destroy() { } }; }
說明:
- 第二種和第三種類似,均實現了
AbstractFilterRegistrationBean
接口,而該接口間接實現了ServletContextInitializer
,springboot在啟動容器后會查找實現該接口的bean,並調用onStartup()
方法添加自定義的Filter,兩則的區別DelegatingFilterProxyRegistrationBean
通過傳入的proxyFilter名字,在WebApplicationContext
查找該Fillter Bean,並通過DelegatingFilterProxy
生成基於該Bean的代理Filter對象,
而FilterRegistrationBean
則是直接設置一個Filter,因此該Filter可以有spring容器管理,也可不用spring管理
注意:如果Filter聲明為一個Bean,則不需要定義為FilterRegistrationBean
,也會被spring發現並添加,就是方法四,該方式無法定義攔截規則等,默認全局,慎用
EmbeddedWebApplicationContext 容器啟動后執行 springboot 2.0 變更為ServletWebServerApplicationContext
private void selfInitialize(ServletContext servletContext) throws ServletException { prepareEmbeddedWebApplicationContext(servletContext); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes( beanFactory); WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, getServletContext()); existingScopes.restore(); WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, getServletContext()); for (ServletContextInitializer beans : getServletContextInitializerBeans()) { beans.onStartup(servletContext); } }
getServletContextInitializerBeans() 會返回實現了ServletContextInitializer
接口的集合,同時初始化一些數據,如下:
public ServletContextInitializerBeans(ListableBeanFactory beanFactory) { this.initializers = new LinkedMultiValueMap<Class<?>, ServletContextInitializer>(); addServletContextInitializerBeans(beanFactory); addAdaptableBeans(beanFactory); List<ServletContextInitializer> sortedInitializers = new ArrayList<ServletContextInitializer>(); for (Map.Entry<?, List<ServletContextInitializer>> entry : this.initializers .entrySet()) { AnnotationAwareOrderComparator.sort(entry.getValue()); sortedInitializers.addAll(entry.getValue()); } this.sortedList = Collections.unmodifiableList(sortedInitializers); }
addAdaptableBeans
addServletContextInitializerBeans
在調用onStartup()方法之前會添加Filter與Servlet,注意Filter與Servlet必須已經聲明為Bean
- 第一種則最終也是采用第二種方式,區別就是在springboot啟動時將掃描到的包路徑作為入參傳遞給
ServletComponentRegisteringPostProcessor
而該類實現了BeanFactoryPostProcessor
接口,因此在BeanFactory初始化后,會調用postProcessBeanFactory()
方法,在該方法中通過之前傳入的包來掃描相應的類,並將@WebFilter
的類由相應的處理器轉換為FilterRegistrationBean
ServletComponentRegisteringPostProcessor
ServletComponentRegisteringPostProcessor(Set<String> packagesToScan) { this.packagesToScan = packagesToScan; } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { if (isRunningInEmbeddedContainer()) { 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 ScannedGenericBeanDefinition) { for (ServletComponentHandler handler : handlers) { handler.handle(((ScannedGenericBeanDefinition) candidate), (BeanDefinitionRegistry) this.applicationContext); } } } }
WebFilterHandler
WebFilterHandler() { super(WebFilter.class); } @Override public void doHandle(Map<String, Object> attributes, ScannedGenericBeanDefinition 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); builder.addPropertyValue("servletNames", attributes.get("servletNames")); builder.addPropertyValue("urlPatterns", extractUrlPatterns("urlPatterns", attributes)); registry.registerBeanDefinition(name, builder.getBeanDefinition()); }
題外話
添加自定義Servlet 也可采用方法一@WebServlet
或者ServletRegistrationBean
添加自定義Listener也可以采用方法一@WebListener
或者ServletListenerRegistrationBean
,注意監聽事件是泛型