Because springboot is based on servlet 3.0+, the embedded tomcat container cannot configure Filter in web.xml as before. This article is based on springboot 1.5.6
First
@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); } }
- The package path scanned by @ServletComponentScan must contain the Filter
Second
@Configuration public class FilterConfig { @Bean public FilterRegistrationBean filterRegistrationBean(){ FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new MyFilter2()); bean.addUrlPatterns("/*"); return bean; } }
Third
@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; }
Method 4
@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() { } }; }
Explain:
- Similar to the second and third, both implements the AbstractFilterRegistrationBean interface, which indirectly implements the ServletContextInitializer, where springboot looks for the beans that implement the interface after starting the container and calls the onStartup() method to add a custom filter. The difference between the two is that DelegatingFilterProxyRegistrationBean uses the proxyFilter name passed in to the WebApplicationContainerExt finds the Fillter Bean and generates a proxy Filter object based on it through DelegatingFilterProxy.
FilterRegistrationBean, on the other hand, sets a Filter directly, so it can be managed by a spring container or not by a spring
Note: If a Filter is declared as a Bean, it does not need to be defined as a FilterRegistrationBean and will also be discovered and added by spring. Method 4, which does not define interception rules, etc. Default global, use caution
Change execution springboot 2.0 to ServletWebServerApplicationContext after the EmbeddedWebApplicationContext container starts
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() returns a collection that implements the ServletContextInitializer interface and initializes some data as follows:
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 adds Filter and Servlet before calling onStartup() method, note that Filter and Servlet must have been declared as Bean
- The first is ultimately the second, except that when springboot starts, the scanned package path is passed as an input to ServletComponentRegisteringPostProcessor, which implements the BeanFactoryPostProcessor interface, so after BeanFactory initializes, the postProcessBeanFactory() method is called, in which the corresponding class is scanned through the previously incoming package.And convert the @WebFilter class from the corresponding processor to a 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()); }
Off-topic topic
Adding a custom Servlet can also take method 1@WebServlet or ServletRegistrationBean
Adding a custom Listener can also take method 1@WebListener or ServletListenerRegistrationBean, noting that listening events are generic
Author: Ergo is fierce
Link: https://www.jianshu.com/p/3d421fbce734
Source: Short Book
Copyright belongs to the author.For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.