百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

spring中的拦截器(HandlerInterceptor+MethodInterceptor)

yuyutoo 2024-11-12 14:57 9 浏览 0 评论

1. 过滤器跟拦截器的区别

在说拦截器之前,不得不说一下过滤器,有时候往往被这两个词搞得头大。

其实我们最先接触的就是过滤器,还记得web.xml中配置的<filter>吗~

你应该知道spring mvc的拦截器是只拦截controller而不拦截jsp,html 页面文件的,如果想要拦截那怎么办?

这就用到过滤器filter了,filter是在servlet前执行的,你也可以理解成过滤器中包含拦截器,一个请求过来 ,先进行过滤器处理,看程序是否受理该请求 。 过滤器放过后 , 程序中的拦截器进行处理 。

(1)过滤器(Filter):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西。定义这些要求的工具,就是过滤器。(理解:就是一堆字母中取一个B)

(2)拦截器(Interceptor):在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。(理解:就是一堆字母中,干预他,通过验证的少点,顺便干点别的东西)。

         │   ▲
         ▼   │
       ┌───────┐
       │Filter1│
       └───────┘
         │   ▲
         ▼   │
       ┌───────┐
┌ ─ ─ ─│Filter2│─ ─ ─ ─ ─ ─ ─ ─ ┐
       └───────┘
│        │   ▲                  │
         ▼   │
│ ┌─────────────────┐           │
  │DispatcherServlet│<───┐
│ └─────────────────┘    │      │
   │              ┌────────────┐
│  │              │ModelAndView││
   │              └────────────┘
│  │                     ▲      │
   │    ┌───────────┐    │
│  ├───>│Controller1│────┤      │
   │    └───────────┘    │
│  │                     │      │
   │    ┌───────────┐    │
│  └───>│Controller2│────┘      │
        └───────────┘
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘

上图虚线框就是Filter2的拦截范围,Filter组件实际上并不知道后续内部处理是通过Spring MVC提供的DispatcherServlet还是其他Servlet组件,因为Filter是Servlet规范定义的标准组件,它可以应用在任何基于Servlet的程序中。

如果只基于Spring MVC开发应用程序,还可以使用Spring MVC提供的一种功能类似Filter的拦截器:Interceptor。和Filter相比,Interceptor拦截范围不是后续整个处理流程,而是仅针对Controller拦截:

       │   ▲
       ▼   │
     ┌───────┐
     │Filter1│
     └───────┘
       │   ▲
       ▼   │
     ┌───────┐
     │Filter2│
     └───────┘
       │   ▲
       ▼   │
┌─────────────────┐
│DispatcherServlet│<───┐
└─────────────────┘    │
 │              ┌────────────┐
 │              │ModelAndView│
 │              └────────────┘
 │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ┐ ▲
 │    ┌───────────┐    │
 ├─┼─>│Controller1│──┼─┤
 │    └───────────┘    │
 │ │                 │ │
 │    ┌───────────┐    │
 └─┼─>│Controller2│──┼─┘
      └───────────┘
   └ ─ ─ ─ ─ ─ ─ ─ ─ ┘

2. spring中的拦截器

在web开发中,拦截器是经常用到的功能。它可以帮我们验证是否登陆、预先设置数据以及统计方法的执行效率等等。

今天就来详细的谈一下spring中的拦截器。spring中拦截器主要分两种,一个是HandlerInterceptor,一个是MethodInterceptor。

2.1 HandlerInterceptor拦截器

HandlerInterceptor是springMVC项目中的拦截器,它拦截的目标是请求的地址,比MethodInterceptor先执行。

实现一个HandlerInterceptor拦截器可以直接实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter类。

这两种方法殊途同归,其实HandlerInterceptorAdapter也就是声明了HandlerInterceptor接口中所有方法的默认实现,而我们在继承他之后只需要重写必要的方法。

下面就是HandlerInterceptorAdapter的代码,可以看到一个方法只是默认返回true,另外两个是空方法:

public abstract class HandlerInterceptorAdapter implements HandlerInterceptor {  
  
    /** 
     * This implementation always returns <code>true</code>. 
     */  
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)  
        throws Exception {  
        return true;  
    }  
  
    /** 
     * This implementation is empty. 
     */  
    public void postHandle(  
            HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)  
            throws Exception {  
    }  
  
    /** 
     * This implementation is empty. 
     */  
    public void afterCompletion(  
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)  
            throws Exception {  
    }  
  
}  

这三个方法都是干什么的,有什么作用,什么时候调用,不同的拦截器之间是怎样的调用顺序呢?

先补一张图:

2.2 MethodInterceptor拦截器

MethodInterceptor是AOP项目中的拦截器,它拦截的目标是方法,即使不是controller中的方法。实现MethodInterceptor拦截器大致也分为两种,一种是实现MethodInterceptor接口,另一种利用AspectJ的注解或配置。

下面是第一种方法的示例

public class MethodInvokeInterceptor implements MethodInterceptor {  
    @Override  
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {  
        System.out.println("before method invoke");  
        Object object = methodInvocation.proceed();  
        System.out.println("after method invoke");  
        return object;  
    }  
}  

下面是基于注解的AspectJ方式

@Component  
@Aspect  
public class AutoAspectJInterceptor {  
  
    @Around("execution (* com.test.controller..*.*(..))")  
    public Object around(ProceedingJoinPoint point) throws Throwable{  
        System.out.println("AutoAspectJInterceptor begin around");  
        Object object = point.proceed();  
        System.out.println("AutoAspectJInterceptor end around");  
        return object;  
    }  
     
}  

下面是一个用于支持AspectJ方式拦截的普通的bean,当然你也可以在配置文件中声明这个bean

@Component  
 public class AspectJInterceptor {  
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {  
        System.out.println("AspectJInterceptor around before");  
        Object object = proceedingJoinPoint.proceed();  
        System.out.println("AspectJInterceptor around after");  
        return object;  
    }  
}  

当然,这一切都离不开配置,具体看配置中的注释

<!-- 自定义拦截器 ,先过mvc:interceptors-->  
    <bean id="methodInvokeInterceptor" class="com.test.interceptor.MethodInvokeInterceptor"/>  
    <bean id="aspectInterceptor" class="com.test.interceptor.AspectJInterceptor"/>  
  
    <aop:config>  
        <!--切入点,controlller -->  
        <aop:pointcut id="pointcut_test"   expression="execution(* com.test.controller..*.*(..))" />  
        <!--在该切入点使用自定义拦截器 ,按照先后顺序执行 -->  
        <aop:advisor pointcut-ref="pointcut_test" advice-ref="methodInvokeInterceptor" />  
  
  
        <aop:aspect ref="aspectInterceptor">  
            <aop:around method="around" pointcut="execution(* com.test.controller..*.*(..))"/>  
        </aop:aspect>  
    </aop:config>  
    <!-- 自动扫描使用了aspectj注解的类 -->  
    <aop:aspectj-autoproxy/>  

通过上面的配置三个MethodInterceptor就能正常工作了。其实,这两种实现方最终...没错,还是殊途同归。

aspectj的拦截器会被解析成AOP中的advice,最终被适配成MethodInterceptor,详细的过程请参考springAOP的实现。

3. 实例选择拦截器

项目中采用Interceptor来过滤URL来决定哪些可以在不登录的情况下访问,哪些必须要登录才可以访问;

3.1 HandlerInterceptor方式

public class SessionTimeoutInterceptor implements HandlerInterceptor {
     .........
}

此时需要在servlet.xml中配置<mvc:interceptor>

3.2 MethodInterceptor注解Aspect方式

@Component
@Aspect
public void class BindingResultAop{
    ........
}

同时在servlet.xml中配置
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

经测试发现,interceptor先于AOP执行。

4. 谈一谈区别

上面的两种拦截器都能起到拦截的效果,但是他们拦截的目标不一样,实现的机制不同,所以有的时候适用不同的场景。

HandlerInterceptoer拦截的是请求地址,所以针对请求地址做一些验证、预处理等操作比较合适。当你需要统计请求的响应时间时MethodInterceptor将不太容易做到,因为它可能跨越很多方法或者只涉及到已经定义好的方法中一部分代码。MethodInterceptor利用的是AOP的实现机制,在本文中只说明了使用方式,关于原理和机制方面介绍得比较少,因为要说清楚这些需要讲出AOP的相当一部分内容。在对一些普通的方法上的拦截HandlerInterceptoer就无能为力了,这时候只能利用AOP的MethodInterceptor。


另外,还有一个跟拦截器类似的东西----Filter。Filter是Servlet规范规定的,不属于spring框架,也是用于请求的拦截。但是它适合更粗粒度的拦截,在请求前后做一些编解码处理、日志记录等。而拦截器则可以提供更细粒度的,更加灵活的,针对某些请求、某些方法的组合的解决方案。


另外的另外,用过人人网的ROSE框架的人都会非常喜欢它的拦截器功能。因为它实现了全注解的方式,只要在类的名字上加上拦截器的注解即表示这是一个拦截器。而使用这个拦截器的方法或者controller也只需在方法或controller的上面加上这个拦截器的注解。其实这是一个关注点的转变,spring的切面控制在配置文件中,配置文件关注哪些地方需要拦截。而在ROSE中,则是在需要拦截的地方关注我要被谁拦截。

相关推荐

对volatile,synchronized,AQS的加锁解锁原理的一些理解

一、为什么要加锁,要实现同步多线程编程中,有可能会出现多个线程同时访问同一个共享、可变资源的情况,这个资源我们称之其为临界资源;这种资源可能是:对象、变量、文件等。...

注意,不能错过的CAS+volatile实现同步代码块

前言:最近看到有人说可以使用CAS+volatile实现同步代码块。心想,确实是可以实现的呀!因为AbstractQueuedSynchronizer(简称AQS)内部就是通过CAS+...

面试并发volatile关键字时,我们应该具备哪些谈资?

提前发现更多精彩内容,请访问https://dayarch.top/提前发现更多精彩内容,请访问https://dayarch.top/提前发现更多精彩内容,请访问https://dayarch...

无锁同步-JAVA之Volatile、Atomic和CAS

1、概要本文是无锁同步系列文章的第二篇,主要探讨JAVA中的原子操作,以及如何进行无锁同步。关于JAVA中的原子操作,我们很容易想到的是Volatile变量、java.util.concurrent....

C/C++面试题(二):std::atomic与volatile

volatile是C/C++中的一个关键字,用于告知编译器某个变量的值可能会在程序的控制之外被意外修改(例如被硬件、中断服务程序、多线程环境或其他外部代理)。为了防止编译器对代码进行某些可能破坏...

VOCs(Volatile Organic Compounds)挥发性有机化合物及测试方法

经常看到一些三防漆、涂料、油漆类产品的介绍中提到VOC、VOCs等概念,那么什么是VOC、VOCs和TVOC,VOCs主要包括哪些物质?VOCs的来源有哪些?VOCs的危害及国家标准是什么?一、V...

对volatile 及happen—before的理解

happen—before规则介绍Java...

这一篇我们来了解Synchronized、Volatile、Final关键字

题外话:蓝银王觉醒了!!--来自于一个斗罗大陆动漫爱好者(鹅,打钱!)湿兄这两天回家了,办了点大事,回来的时候我弟弟还舍不得我,哭着不愿意让我回京(我弟还是小学),我也心里很不舍,但是还是要回京奋斗...

关于 Java 关键字 volatile 的总结

1什么是volatilevolatile是Java的一个关键字,它提供了一种轻量级的同步机制。相比于重量级锁synchronized,volatile更为轻量级,因为它不会引起线程上下文...

大白话聊聊Java并发面试问题之volatile到底是什么?

用最简单的大白话,加上多张图给大家说一下,volatile到底是什么?...

为什么要有volatile关键字(volatile 关键字为什么不能保证原子性)

在嵌入式编程和多线程编程中,我们常会见到volatile关键字声明的变量。下面说一下volatile关键字的作用:1.保持变量内存可见简而言之就是用volatile声明的变量会告诉编译器和处理器,这个...

Java的volatile到底怎么理解?(java volatitle)

我们都知道,在Java中有很多的关键字,比如synchronize比如volatile,这些都是一些比较关键的,还有final,今天我们就来聊一下这个volatile因为这个vo...

Java多线程编程中的volatile关键字:解密神秘的共享内存

Java多线程编程中的volatile关键字:解密神秘的共享内存在Java多线程编程的世界里,volatile关键字就像一位低调却至关重要的守护者。它默默无闻地站岗放哨,确保多个线程之间能够正确地共享...

你了解volatile关键字的作用吗?(关键字volatile有什么含意?并举出三个不同的例子?)

【死记硬背】volatile关键字主要用于保持内存的变量可见性和禁止重排序。变量可见性:当一个线程改变了变量的值,那么新的值对于其他线程也是可以立即获取到的。禁止重排序:...

谈谈你对volatile 关键字作用和原理的理解

一位6年工作经验的小伙伴,在某里二面的时候被问到“volatile”关键字。然后,就没有然后了…同样,还有一位4年的小伙伴,去某团面试也被问到“volatile关键字“。然后,也没有然后了…...

取消回复欢迎 发表评论: