目录

Filter

过滤器:依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等

过滤器的运行是依赖于servlet容器的,跟springmvc等框架并没有关系

多个过滤器的执行顺序跟xml文件中定义的先后关系有关

Servlet 生命周期

Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:

  • Servlet 初始化后调用 init () 方法。
  • Servlet 调用 service() 方法来处理客户端的请求。
  • Servlet 销毁前调用 destroy() 方法。
  • 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。

/images/spring/filter/Servlet-LifeCycle.jpg

@WebFilter

Servlet3.0新增的注解,原先实现过滤器,需要在web.xml中进行配置,而现在通过此注解,启动时会自动扫描自动注册。 需要在启动类加入@ServletComponentScan注解。

1
2
3
4
@WebFilter(filterName="customFilter",urlPatterns={"/*"})
public class CustomFilter implements Filter{

}

原本使用web.xml配置过滤器时,是可指定执行顺序的,但使用@WebFilter时,如果要控制顺序可以通过FilterRegistrationBean进行过滤器的注册。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
    @Bean
    public FilterRegistrationBean  filterRegistrationBean() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        //当过滤器有注入其他bean类时,可直接通过@bean的方式进行实体类过滤器,这样不可自动注入过滤器使用的其他bean类。
        //当然,若无其他bean需要获取时,可直接new CustomFilter(),也可使用getBean的方式。
        registration.setFilter(customFilter());
        //过滤器名称
        registration.setName("customFilter");
        //拦截路径
        registration.addUrlPatterns("/*");
        //设置顺序
        registration.setOrder(10);
        return registration;
    }

    @Bean
    public Filter customFilter() {
        return new CustomFilter();
    }

排序

  • 可以通过过滤器的类名进行约定排序
  • FilterRegistrationBean.setOrder

@ServletComponentScan 启动方式

在SpringBootApplication上使用@ServletComponentScan注解后,Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册到嵌入式Servlet容器中,无需其他代码。

Servlet 3.0 注解

  • javax.servlet.annotation.WebFilter
  • javax.servlet.annotation.WebListener
  • javax.servlet.annotation.WebServlet

Servlet3.0作为J2EE 6规范一部分,并随J2EE6一起发布,@WebListener是该注解用于将类声明为监听器,是Servlet3.0的新特性,不需要在web.xml进行配置,简化了配置。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Slf4j
@SpringBootApplication
@ServletComponentScan
public class Jdk17Application {

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}

@WebServlet(name="TestServlet", urlPatterns="/hello")
public class TestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        response.getOutputStream().write("hello");
        log.info("doGet");
    }
}

@WebFilter("/hello")
public class HelloFilter implements Filter {

    @Override
    public void doFilter(
      ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
      throws IOException, ServletException {
        servletResponse
          .getOutputStream()
          .print("filtering");
        filterChain.doFilter(servletRequest, servletResponse);
    }

}

@WebFilter @ServletComponentScan ServletComponentScanRegistrar

可以看见,它是一个ImportBeanDefinitionRegistrar的实现类,ImportBeanDefinitionRegistrar可以动态地装载Bean。再来看看ServletComponentRegisteringPostProcessor类,此类是个BeanFactoryPostProcessor,BeanFactory的后置处理器,简单理解就是扩展点吧。启动的时候会调用postProcessBeanFactory方法。 ServletComponentRegisteringPostProcessor 简单来说,它的作用就是:扫描被@WebServlet、@WebFilter及@WebListener注解的类,最后通过对应的 ServletRegistrationBean、FilterRegistrationBean 及 ServletListenerRegistrationBean 进行注册。

拦截器(Interceptor)是基于Java的反射机制,而过滤器(Filter)是基于函数回调。

  • Filter需要在web.xml中配置,依赖于Servlet;
  • Interceptor需要在SpringMVC中配置,依赖于框架;
  • Filter的执行顺序在Interceptor之前

@WebListener用法

该注解用于将类声明为监听器,被 @WebListener 标注的类必须实现以下至少一个接口:

  • ServletContextListener
  • ServletContextAttributeListener
  • ServletRequestListener
  • ServletRequestAttributeListener
  • HttpSessionListener
  • HttpSessionAttributeListener
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@WebListener
public class AttrListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        servletContextEvent
          .getServletContext()
          .setAttribute("servlet-context-attr","test");
    }
}