# 过滤器和拦截器的区别
-
过滤器和拦截器触发时机不一样,过滤器是在请求进入容器后,但请求进入 servlet 之前进行预处理的。请求结束返回也是,是在 servlet 处理完后,返回给前端之前。
-
拦截器可以获取 IOC 容器中的各个 bean ,而过滤器就不行,因为拦截器是 spring 提供并管理的, spring 的功能可以被拦截器使用,在拦截器里注入一个 service ,可以调用业务逻辑。而过滤器是 JavaEE 标准,只需依赖 servlet api ,不需要依赖 spring 。
-
过滤器的实现基于 回调函数 。而 拦截器(代理模式) 的实现基于反射
-
Filter 是依赖于 Servlet 容器,属于 Servlet 规范的一部分,而拦截器则是独立存在的,可以在任何情况下使用。
-
Filter 的执行由 Servlet 容器回调完成,而拦截器通常通过动态代理(反射)的方式来执行。
-
Filter 的生命周期由 Servlet 容器管理,而拦截器则可以通过 IoC 容器来管理,因此可以通过注入等方式来获取其他 Bean 的实例,因此使用会更方便。
# SpringBoot 使用过滤器
两种方式:
- 使用
spring boot 提供的 FilterRegistrationBean 注册 Filter
- 使用原生
servlet 注解定义 Filter
两种方式的本质都是一样的,都是去 FilterRegistrationBean 注册自定义 Filter
方式一: (使用 spring boot 提供的 FilterRegistrationBean 注册 Filter )
①. 先定义 Filter :
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
| package com.cy.springboot01.filter;
import javax.servlet.*; import java.io.IOException;
public class MyFilter implements Filter {
@Override public void init(FilterConfig filterConfig) throws ServletException {
}
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("filter1"); filterChain.doFilter(servletRequest,servletResponse); }
@Override public void destroy() {
} }
|
②、注册自定义 Filter
1 2 3 4 5 6 7 8 9 10
| @Configuration public class FilterConfig {
@Bean public FilterRegistrationBean registrationBean() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter()); filterRegistrationBean.addUrlPatterns("/*"); return filterRegistrationBean; } }
|
方式一的 ①②步骤 可以用下面这段代码代替:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Configuration public class FilterConfig { @Bean public FilterRegistrationBean registFilter() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new LogCostFilter()); registration.addUrlPatterns("/*"); registration.setName("LogCostFilter"); registration.setOrder(1); return registration; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class LogCostFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { long start = System.currentTimeMillis(); filterChain.doFilter(servletRequest,servletResponse); System.out.println("Execute cost="+(System.currentTimeMillis()-start)); } @Override public void destroy() { } }
|
方式二:(使用原生 servlet 注解定义 Filter )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @Component
@WebFilter(filterName = "my2Filter" ,urlPatterns = "/*") public class My2Filter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException {
} @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("filter2"); } @Override public void destroy() {
} }
|
这里直接用 @WebFilter 就可以进行配置,同样,可以设置 url 匹配模式,过滤器名称等。这里需要注意一点的是 @WebFilter 这个注解是 Servlet3.0 的规范,并不是 Spring boot 提供的。除了这个注解以外,我们还需在启动类中加另外一个注解: @ServletComponetScan ,指定扫描的包。
# SpringBoot 配置拦截器
首先我们实现拦截器类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class LogCostInterceptor implements HandlerInterceptor { long start = System.currentTimeMillis(); @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { start = System.currentTimeMillis(); return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { System.out.println("Interceptor cost="+(System.currentTimeMillis()-start)); } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }
|
我们还需要实现 HandlerInterceptor 这个接口,这个接口包括三个方法, preHandle 是请求执行前执行的, postHandler 是请求结束执行的,但只有 preHandle 方法返回 true 的时候才会执行, afterCompletion 是视图渲染完成后才执行,同样需要 preHandle 返回 true ,
该方法通常用于清理资源等工作。除了实现上面的接口外,我们还需对其进行配置:
1 2 3 4 5 6 7 8 9
| @Configuration public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LogCostInterceptor()).addPathPatterns("/**"); super.addInterceptors(registry); } }
|
这里我们实现了 WebMvcConfigurer ,这里我们重写了 addInterceptors 这个方法,进行拦截器的配置,主要配置项就两个,一个是指定拦截器,第二个是指定拦截的 URL 。