zoukankan      html  css  js  c++  java
  • 关于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 ,注意监听事件是泛型
  • 相关阅读:
    领导力包括哪些能力?如何提升领导力?
    管理者如何让员工服从?
    常用查询语句
    BZOJ2190 SDOI2008 仪仗队 gcd,欧拉函数
    使用python来操作redis用法详解
    int指令
    浏览器打开exe文件
    feiQ发送信息
    【转】Notepad++ 中文查找(中文搜索)问题解决方法
    【转】Java基本概念:集合类 List/Set/Map...的区别
  • 原文地址:https://www.cnblogs.com/wpcnblog/p/12358112.html
Copyright © 2011-2022 走看看