专栏名称: java那些事
分享java开发中常用的技术,分享软件开发中各种新技术的应用方法。每天推送java技术相关或者互联网相关文章。关注“java那些事”,让自己做一个潮流的java技术人!《java程序员由笨鸟到菜鸟》系列文章火热更新中。
目录
相关文章推荐
Java编程精选  ·  前阿里员工:内推了个38岁的研发,简历到HR ... ·  14 小时前  
芋道源码  ·  SpringBoot3.4.0 结构化日志详解 ·  18 小时前  
Java编程精选  ·  字节员工自曝:再强调一遍OD ... ·  2 天前  
芋道源码  ·  SpringBoot CORS ... ·  2 天前  
芋道源码  ·  DeepSeek 全面指南:95% ... ·  4 天前  
51好读  ›  专栏  ›  java那些事

Spring Boot实战:拦截器与过滤器

java那些事  · 公众号  · Java  · 2019-01-18 16:00

正文

作者: liuxiaopeng

链接:http://www.cnblogs.com/paddix


一、拦截器与过滤器

在讲Spring boot之前,我们先了解一下过滤器和拦截器。这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较大的。在分析两者的区别之前,我们先理解一下AOP的概念,AOP不是一种具体的技术,而是一种编程思想。在面向对象编程的过程中,我们很容易通过继承、多态来解决纵向扩展。

但是对于横向的功能,比如,在所有的service方法中开启事务,或者统一记录日志等功能,面向对象的是无法解决的。所以AOP——面向切面编程其实是面向对象编程思想的一个补充。而我们今天讲的过滤器和拦截器都属于面向切面编程的具体实现。

而两者的主要区别包括以下几个方面:

  • Filter是依赖于Servlet容器,属于Servlet规范的一部分,而拦截器则是独立存在的,可以在任何情况下使用。

  • Filter的执行由Servlet容器回调完成,而拦截器通常通过动态代理的方式来执行。

  • Filter的生命周期由Servlet容器管理,而拦截器则可以通过IoC容器来管理,因此可以通过注入等方式来获取其他Bean的实例,因此使用会更方便。

二、过滤器的配置

现在我们通过过滤器来实现记录请求执行时间的功能,其实现如下:

  1. public class LogCostFilter implements Filter {

  2. @Override

  3. public void init ( FilterConfig filterConfig ) throws ServletException {


  4. }


  5. @Override

  6. public void doFilter ( ServletRequest servletRequest , ServletResponse servletResponse , FilterChain filterChain ) throws IOException , ServletException {

  7. long start = System . currentTimeMillis ();

  8. filterChain . doFilter ( servletRequest , servletResponse );

  9. System . out . println ( "Execute cost=" +( System . currentTimeMillis ()- start ));

  10. }


  11. @Override

  12. public void destroy () {


  13. }

  14. }

这段代码的逻辑比较简单,就是在方法执行前先记录时间戳,然后通过过滤器链完成请求的执行,在返回结果之间计算执行的时间。这里需要主要,这个类必须继承Filter类,这个是Servlet的规范,这个跟以前的Web项目没区别。

但是,有了过滤器类以后,以前的web项目可以在web.xml中进行配置,但是spring boot项目并没有web.xml这个文件,那怎么配置?在Spring boot中,我们需要FilterRegistrationBean来完成配置。其实现过程如下:

  1. @Configuration

  2. public class FilterConfig {


  3. @Bean

  4. public FilterRegistrationBean registFilter () {

  5. FilterRegistrationBean registration = new FilterRegistrationBean ();

  6. registration . setFilter ( new LogCostFilter ());

  7. registration . addUrlPatterns ( "/*" );

  8. registration . setName ( "LogCostFilter" );

  9. registration . setOrder ( 1 );

  10. return registration ;

  11. }


  12. }

这样配置就完成了,需要配置的选项主要包括实例化Filter类,然后指定url的匹配模式,设置过滤器名称和执行顺序,这个过程和在web.xml中配置其实没什么区别,只是形式不同而已。现在我们可以启动服务器访问任意URL:

大家可以看到上面的配置已经生效了。除了通过 FilterRegistrationBean 来配置以外,还有一种更直接的办法,直接通过注解就可以完成了:

  1. @WebFilter ( urlPatterns = "/*" , filterName = "logFilter2" )

  2. public class LogCostFilter2 implements Filter {

  3. @Override

  4. public void init ( FilterConfig filterConfig ) throws ServletException {


  5. }


  6. @Override

  7. public void doFilter ( ServletRequest servletRequest , ServletResponse servletResponse , FilterChain filterChain ) throws IOException , ServletException {

  8. long start = System . currentTimeMillis ();

  9. filterChain . doFilter ( servletRequest , servletResponse );

  10. System . out . println ( "LogFilter2 Execute cost=" + ( System . currentTimeMillis () - start ));

  11. }


  12. @Override

  13. public void destroy () {


  14. }

  15. }

这里直接用@WebFilter就可以进行配置,同样,可以设置url匹配模式,过滤器名称等。这里需要注意一点的是@WebFilter这个注解是Servlet3.0的规范,并不是Spring boot提供的。除了这个注解以外,我们还需在配置类中加另外一个注解:@ServletComponetScan,指定扫描的包。

  1. @SpringBootApplication

  2. @MapperScan ( "com.pandy.blog.dao" )

  3. @ServletComponentScan ( "com.pandy.blog.filters" )

  4. public class Application {

  5. public static void main ( String [] args ) throws Exception {

  6. SpringApplication . run ( Application . class , args );

  7. }

  8. }

现在,我们再来访问一下任意URL:

可以看到,我们配置的两个过滤器都生效了。细心的读者会发现,第二个Filter我们并没有指定执行的顺序,但是却在第一个Filter之前执行。这里需要解释一下,@WebFilter这个注解并没有指定执行顺序的属性,其执行顺序依赖于Filter的名称,是根据Filter类名(注意不是配置的filter的名字)的字母顺序倒序排列,并且@WebFilter指定的过滤器优先级都高于FilterRegistrationBean配置的过滤器。有兴趣的朋友可以自己实验一下。

三、拦截器的配置

上面我们已经介绍了过滤器的配置方法,接下来我们再来看看如何配置一个拦截器。我们使用拦截器来实现上面同样的功能,记录请求的执行时间。首先我们实现拦截器类:

  1. public class LogCostInterceptor implements HandlerInterceptor {

  2. long start = System . currentTimeMillis ();

  3. @Override

  4. public boolean preHandle ( HttpServletRequest httpServletRequest , HttpServletResponse httpServletResponse , Object o ) throws Exception {

  5. start = System . currentTimeMillis ();

  6. return true ;

  7. }


  8. @Override







请到「今天看啥」查看全文