關於springboot中添加Filter的方法


由於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 ,注意監聽事件是泛型


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM