Java 拦截器深入了解学习

Java 拦截器深入了解学习

命运总是不如愿。 但往往是在无数的痛苦中,在重重的矛盾和艰难中,才使人成熟起来,坚强起来;虽然这些东西在实际感受中给人带来的并不都是欢乐。 ------------路遥《平凡的世界》

什么是拦截器(Interceptor)

在Spring Boot中,拦截器(Interceptor)是一种用于处理HTTP请求的机制,主要用于执行一些预处理或后处理的逻辑。与AOP不同,拦截器更专注于HTTP请求的处理,而不是面向方法调用等更细粒度的横切关注点。以下是Spring Boot拦截器的详细解释:

1. 拦截器接口:

在Spring Boot中,拦截器需要实现HandlerInterceptor接口。这个接口定义了三个主要的方法:

  • preHandle: 在请求处理之前被调用,用于进行一些预处理操作。
  • postHandle: 在请求处理之后、视图渲染之前被调用,用于进行一些后处理操作。
  • afterCompletion: 在整个请求处理完成后被调用,用于进行一些资源清理操作。

2. 配置拦截器:

在Spring Boot中配置拦截器主要通过实现WebMvcConfigurer接口,并覆盖addInterceptors方法。下面是一个简单的例子:

java 复制代码
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/api/**")  // 拦截的路径
                .excludePathPatterns("/public/**");  // 排除的路径
    }
}

在上述例子中,MyInterceptor 是实现了HandlerInterceptor接口的拦截器类。通过addPathPatterns指定需要拦截的路径,通过excludePathPatterns指定排除的路径。

3. 拦截器的实现:

拦截器的实现类需要实现HandlerInterceptor接口,并覆盖其中的方法,如下所示:

java 复制代码
public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 在请求处理之前执行的逻辑
        return true; // 返回true表示继续执行后续操作,返回false表示中断请求处理
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 在请求处理之后执行的逻辑,视图渲染之前
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 在整个请求处理完成后执行的逻辑,包括视图渲染之后
    }
}

4. 使用场景:

拦截器常用于:

  • 身份验证和权限控制
  • 日志记录
  • 统一异常处理
  • 请求参数处理等

拦截器(Interceptor)和切面(AOP)之间的区别

尽管拦截器(Interceptor)和AOP(面向切面编程)都是用于处理横切关注点的机制,但它们之间存在一些关键的区别。下面是它们之间的主要区别:

1. 关注点:

  • 拦截器: 主要关注HTTP请求的处理,通常用于预处理、后处理、日志记录等与HTTP请求相关的操作。拦截器工作在Controller层之上,能够截获请求的生命周期。

  • AOP: 关注点更广泛,可以应用于方法调用、对象的创建、属性的获取等各个层面。AOP更灵活,可以在更细粒度的操作上进行横切关注点的处理。

2. 作用范围:

  • 拦截器: 主要作用于HTTP请求处理,对Controller层的处理有直接影响。拦截器的作用范围更集中。

  • AOP: 可以作用于整个应用程序的多个模块,跨足多个层次。AOP的作用范围更广泛,不仅限于HTTP请求。

3. 使用场景:

  • 拦截器: 常用于身份验证、权限控制、日志记录等与HTTP请求生命周期相关的场景。

  • AOP: 常用于横切关注点,如日志记录、性能监控、事务管理等。AOP更适合处理那些与业务逻辑解耦的横切关注点。

4. 实现方式:

  • 拦截器: 在Spring Boot中通过实现HandlerInterceptor接口来创建拦截器。

  • AOP: 在Spring中,可以通过配置切面和通知,使用@Aspect注解等方式实现AOP。

5. 粒度:

  • 拦截器: 作用于整个请求处理阶段,较为粗粒度。

  • AOP: 可以根据需要选择切入点,可以是方法调用、对象的创建等,较为细粒度。

6. 依赖:

  • 拦截器: 主要依赖于Spring MVC框架,用于处理HTTP请求。

  • AOP: 可以独立于任何框架使用,不仅限于Spring框架。

综上所述,拦截器和AOP在关注点、作用范围、实现方式等方面存在差异,开发者可以根据具体需求选择合适的机制。通常情况下,如果只涉及HTTP请求处理相关的横切关注点,拦截器是一个较为合适的选择。如果需要更广泛的横切关注点处理,AOP可能更适合。

所以啊,可能很多时候可能AOP用的更多一些,比如若依的日志系统用的就是AOP切面进行实现,再言之,可能拦截器更加适合权限管理

一般可以这样理解,但并不是绝对的。虽然AOP通常被用于实现横切关注点的功能性需求,例如日志、事务、性能监控等,而拦截器则更常用于处理与HTTP请求生命周期相关的事务,如权限控制。

AOP的功能性:

  • 日志记录: 可以通过AOP实现在方法调用前后记录日志。
  • 事务管理: 可以使用AOP确保一组操作在事务的上下文中执行。
  • 性能监控: 可以通过AOP监控方法的执行时间等性能指标。

拦截器更适合权限控制:

  • 身份验证和授权: 拦截器可以用于对HTTP请求进行身份验证和授权,例如检查用户是否具有执行某个操作的权限。
  • 请求预处理: 可以在拦截器中进行请求的预处理,例如解析请求参数、检查请求头等。

虽然上述是一种常见的用法,但并不是绝对的规则。在实际应用中,AOP和拦截器可以灵活结合,根据具体需求进行选择。例如,权限控制可以通过AOP来实现,而拦截器也可以用于实现功能性的需求。

拦截器(Interceptor)的实现

示例一

在Spring Boot中,可以通过实现HandlerInterceptor接口来创建一个拦截器,用于判断请求是否携带了 token。以下是一个简单的例子:

java 复制代码
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TokenInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 从请求头中获取 token
        String token = request.getHeader("Authorization");

        // 判断 token 是否存在
        if (token == null || token.isEmpty()) {
            // 如果不存在,返回未授权状态码,并终止请求
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }

        // 如果存在 token,继续处理请求
        return true;
    }
}

在这个例子中,TokenInterceptor 继承了 HandlerInterceptorAdapter 类,重写了 preHandle 方法。在 preHandle 方法中,从请求头中获取了名为 "Authorization" 的 token,然后判断是否存在。如果不存在,返回未授权状态码(SC_UNAUTHORIZED)并终止请求;如果存在,继续处理请求。

接下来,你需要在配置类中注册这个拦截器:

java 复制代码
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册拦截器,并设置拦截的路径
        registry.addInterceptor(new TokenInterceptor())
                .addPathPatterns("/api/**"); // 设置需要拦截的路径
    }
}

在这个例子中,WebMvcConfig 类实现了 WebMvcConfigurer 接口,并覆盖了 addInterceptors 方法,用于注册拦截器。在 addInterceptors 方法中,通过 registry.addInterceptor(new TokenInterceptor()) 注册了 TokenInterceptor 拦截器,并使用 .addPathPatterns("/api/**") 指定了需要拦截的路径,可以根据实际需求进行修改。

示例二

我们再升级一下,需求是在请求前鉴权,如果没有携带 token 则返回 401,在请求后判断逻辑错误返回 500,并在请求完成后输出日志。

java 复制代码
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TokenInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 从请求头中获取 token
        String token = request.getHeader("Authorization");

        // 判断 token 是否存在
        if (token == null || token.isEmpty()) {
            // 如果不存在,返回未授权状态码并终止请求
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }

        // 在这里可以进行进一步的鉴权逻辑
        // 如果鉴权失败,可以返回 401 并终止请求
        // ...

        return true; // 鉴权通过,继续处理请求
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 请求处理完成后的逻辑
        if (ex != null) {
            // 如果有异常,返回 500 状态码
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            // 这里可以记录日志或进行其他逻辑处理
            System.err.println("Request completed with error: " + ex.getMessage());
        } else {
            // 请求正常完成,可以记录日志或进行其他逻辑处理
            System.out.println("Request completed successfully");
        }
    }
}

在这个示例中,preHandle 方法用于在请求前进行鉴权,如果没有携带 token 则返回 401,如果鉴权失败可以在这里终止请求。afterCompletion 方法用于在请求完成后进行逻辑处理,如果有异常则返回 500 并记录错误日志,否则记录请求正常完成的日志。请根据实际需求进行适当的调整。

相关推荐
努力的小雨1 小时前
把 Windows 桌面图标做成一个会自己运转的小世界
后端
触底反弹1 小时前
深入理解大模型采样:Temperature、Top-K、Top-P 的原理与实战
人工智能·算法·面试
武子康1 小时前
Search Console Platform Properties 扩大 SEO 资产边界:从 Page Ranking 到 Topic Coverage(5 类误读边界 + 3 表数据层设计)
前端·人工智能·后端
大模型码小白1 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
腾渊信息科技公司2 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
沉默王二3 小时前
腾讯一面,我霸气反问:“你说你们在做Agent项目,说说 SubAgent、Plan 模式、Skill 调用这些你们都是怎么做的?”面试官一直在擦汗。。
面试·agent·ai编程
爱笑的源码基地3 小时前
高并发 Redis 缓存门诊HIS系统源码,含财务统计药房进销存
java·程序·门诊系统·诊所系统·云诊所源码
IT_陈寒3 小时前
Vue这个特性差点让我加班到凌晨,谁懂啊
前端·人工智能·后端
段一凡-华北理工大学3 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
码事漫谈4 小时前
1999年的电商前夜和2026年的AI前夜 历史押韵但从不重复
后端