Spring Boot实战:拦截器与过滤器
一、拦截器与过滤器
过滤器和拦截器。这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较大的。
在分析两者的区别之前,我们先理解一下
AOP的概念,AOP不是一种具体的技术,而是一种编程思想。
在面向对象编程的过程中,我们很容易通过继承、多态来解决纵向扩展。 但是对于横向的功能,比如,在所有的service方法中开启事务,或者统一记录日志等功能,面向对象的是无法解决的。所以AOP——面向切面编程其实是面向对象编程思想的一个补充。
**过滤器和拦截器都属于面向切面编程的具体实现。**
而两者的主要区别包括以下几个方面:
1、Filter是依赖于Servlet容器,属于Servlet规范的一部分;而拦截器则是在springmvc中独有的。
2、Filter的执行由Servlet容器回调完成;而拦截器通常通过动态代理的方式来执行。
3、Filter的生命周期由Servlet容器管理,而拦截器则可以通过IoC容器来管理,因此可以通过注入等方式来获取其他Bean的实例,因此使用会更方便。
二、过滤器的配置
现在我们通过过滤器来实现记录请求执行时间的功能,其实现如下:
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("执行时间 =" + (System.currentTimeMillis()-start)); } @Override public void destroy() { } }
这段代码的逻辑比较简单,就是在方法执行前先记录时间戳,然后通过过滤器链完成请求的执行,在返回结果之间计算执行的时间。这里需要主要,这个类必须继承Filter类,这个是Servlet的规范,这个跟以前的Web项目没区别。但是,有了过滤器类以后,以前的web项目可以在web.xml中进行配置,但是spring boot项目并没有web.xml这个文件,那怎么配置?在Spring boot中,我们需要FilterRegistrationBean来完成配置。其实现过程如下:
@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; } }
这样配置就完成了,需要配置的选项主要包括实例化Filter类,然后指定url的匹配模式,设置过滤器名称和执行顺序,这个过程和在web.xml中配置其实没什么区别,只是形式不同而已。现在我们可以启动服务器访问任意URL:
大家可以看到上面的配置已经生效了。除了通过 FilterRegistrationBean 来配置以外,还有一种更直接的办法,直接通过注解就可以完成了:
@WebFilter(urlPatterns = "/*", filterName = "logFilter2") public class LogCostFilter2 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("LogFilter2 Execute cost=" + (System.currentTimeMillis() - start)); } @Override public void destroy() { } }
这里直接用@WebFilter就可以进行配置,同样,可以设置url匹配模式,过滤器名称等。这里需要注意一点的是@WebFilter这个注解是Servlet3.0的规范,并不是Spring boot提供的。除了这个注解以外,我们还需在配置类中加另外一个注解:
@ServletComponetScan,指定扫描的包。
@SpringBootApplication @MapperScan("com.pandy.blog.dao") @ServletComponentScan("com.pandy.blog.filters") public class Application { public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } }
现在,我们再来访问一下任意URL会发现第二个Filter我们并没有指定执行的顺序,但是却在第一个Filter之前执行。
Filter的执行优先级顺序:
- @WebFilter这个注解并没有指定执行顺序的属性,其执行顺序依赖于Filter的名称,是根据Filter类名(注意不是配置的filter的名字)的字母顺序倒序排列;
- 如果我们在.xml文件中配置多个filter的话,过滤器执行的顺序会按照标签的上下顺序执行;
- 如果注解和配置文件的方式并存,注解方式的过滤器会优先于配置文件中配置的过滤器,即:@WebFilter指定的过滤器优先级都高于FilterRegistrationBean配置的过滤器。
三、拦截器的配置
上面我们已经介绍了过滤器的配置方法,接下来我们再来看看如何配置一个拦截器。我们使用拦截器来实现上面同样的功能,记录请求的执行时间。
1.自定义拦截器需要实现
HandlerInterceptor这个接口,这个接口包括三个方法:
preHandle是在请求的处理器方法执行前执行的;
postHandler是处理器结束之后执行的,但只有preHandle方法返回true的时候才会执行;
afterCompletion是视图渲染完成后才执行,同样需要preHandle返回true,该方法通常用于清理资源等工作。
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 { } }
2.对拦截器进行配置:
@Configuration public class InterceptorConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LogCostInterceptor()).addPathPatterns("/**"); super.addInterceptors(registry); } }
这里我们继承了
WebMVCConfigurerAdapter,重写了
addInterceptors方法进行拦截器的配置。主要配置项就两个:
指定拦截器,指定拦截的URL。
现在我们再启动系统访问任意一个URL,通过拦截器实现了和Filter同样的功能。
使用拦截器实现存在的问题:
因为preHandle和postHandle是两个方法,所以我们这里设置了一个共享变量start来存储开始值,但是这样就会存在线程安全问题。
当然,我们可以通过使用
ThreadLocal可以解决多线程情况下同一变量的访问冲突问题。
虽然拦截器在很多场景下优于过滤器,但是在这种场景下,过滤器比拦截器实现起来更简单。
四、总结
无论是过滤器还是拦截器都属于
AOP(面向切面编程)思想的具体实现。也可以使用更灵活的AOP实现技术,即·Aspect·,我们可以通过Aspect来完成更多更强大的功能。
- 点赞
- 收藏
- 分享
- 文章举报
- Spring boot实战:拦截器interceptor与过滤器Filter
- Spring Boot实战:拦截器与过滤器
- SpringBoot使用拦截器、过滤器、监听器
- 【spring-boot神器】第一篇:拦截器,过滤器,监听器,控制器,消息转换器,AOP执行顺序
- spring boot设置过滤器、监听器及拦截器的方法
- Spring Boot (九):过滤器、拦截器、监听器
- SpringBoot中的过滤器和拦截器的实现
- spring boot过滤器、监听器、拦截器、servlet的使用
- [置顶] 一步一步学springboot (六)集成拦截器和过滤器及监听器
- springboot配置:拦截器,监听器,过滤器.
- SpringBoot 注册自定义 过滤器、拦截器、监听器... 等组件到容器的两种方式(springboot2.x)
- spring 4000 boot自定义监听器(listener),过滤器(filter),拦截器(interceptor)。即执行时机、顺序。
- springboot-拦截器-过滤器-Required request body is missing 异常
- springboot中定时器、过滤器、拦截器、servlet
- SpringBoot使用拦截器、过滤器、监听器
- springboot(五)过滤器和拦截器
- SpringBoot(六):过滤器和拦截器
- Springboot中拦截器和过滤器的区别
- springboot关于拦截器或者过滤器无法注入bean的问题
- springboot过滤器和拦截器的实现和区别