Java 拦截器深入了解学习
命运总是不如愿。 但往往是在无数的痛苦中,在重重的矛盾和艰难中,才使人成熟起来,坚强起来;虽然这些东西在实际感受中给人带来的并不都是欢乐。
————路遥《平凡的世界》
什么是拦截器(Interceptor)
在Spring Boot中,拦截器(Interceptor)是一种用于处理HTTP请求的机制,主要用于执行一些预处理或后处理的逻辑。与AOP不同,拦截器更专注于HTTP请求的处理,而不是面向方法调用等更细粒度的横切关注点。以下是Spring Boot拦截器的详细解释:
1. 拦截器接口:
在Spring Boot中,拦截器需要实现HandlerInterceptor
接口。这个接口定义了三个主要的方法:
preHandle
: 在请求处理之前被调用,用于进行一些预处理操作。postHandle
: 在请求处理之后、视图渲染之前被调用,用于进行一些后处理操作。afterCompletion
: 在整个请求处理完成后被调用,用于进行一些资源清理操作。
2. 配置拦截器:
在Spring Boot中配置拦截器主要通过实现WebMvcConfigurer
接口,并覆盖addInterceptors
方法。下面是一个简单的例子:
@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
接口,并覆盖其中的方法,如下所示:
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。以下是一个简单的例子:
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
)并终止请求;如果存在,继续处理请求。
接下来,你需要在配置类中注册这个拦截器:
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,并在请求完成后输出日志。
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 并记录错误日志,否则记录请求正常完成的日志。请根据实际需求进行适当的调整。