1 简述
相对于web过滤器,spring 拦截器更接近切面编程,拦截方法不仅可以获取request,response参数,还包含handler参数,通过handler参数可以获取到匹配本次请求controller类的method相关信息,依据该部分信息,可以实施一些更丰富的切面逻辑。
跟spring aop功能很类似,但它只是对http请求做拦截处理。
2. 配置
首先,创建一个实现HandlerInterceptor接口的拦截器类,如下:
@Component
public class DemoInterceptor1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(String.format("DemoInterceptor1.preHandle, url:%s", request.getRequestURL()));
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println(String.format("DemoInterceptor1.postHandle, url:%s", request.getRequestURL()));
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println(String.format("DemoInterceptor1.afterCompletion, url:%s, ex:%s", request.getRequestURL(), ex));
}
}
然后,注册、配置拦截器,将拦截器与具体http请求url路径关联,支持匹配、排除组合方式配置,如果有多个拦截器,可通过order方法,按从小到大排序,如下:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private DemoInterceptor1 demoInterceptor1;
@Autowired
private DemoInterceptor2 demoInterceptor2;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(demoInterceptor1).addPathPatterns("/**").excludePathPatterns("/user/info").order(2);
registry.addInterceptor(demoInterceptor2).addPathPatterns("/**").excludePathPatterns("/user/info").order(1);
}
}
3. 功能
spring 拦截器,在功能上跟过滤器很相似,都是对http请求做预处理、拦截处理。
下面是http请求大致流量:
在流程上,靠后一些,但仍在具体的Controller相关处理逻辑之前,仍在http输入流ServletInputStream解析之前。
spring 拦截器的优势在于,它属于spring框架,可以充分利用spring提供的资源、比如spring中bean对象注入,通过handler可了解,它由那个Controller的method处理,这方面跟spring aop能力基本是一样的。
相对于Filter而言,spring 拦截器更接近业务,适合与业务有更高的相关度,依此来判断具体采用那种技术的原则之一。
以下是一个简单例子
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(String.format("preHandle, url:%s", request.getRequestURL()));
if (!this.isPermit(request)) {
response.setCharacterEncoding(java.nio.charset.StandardCharsets.UTF_8.name());
response.getWriter().write("请求被拒绝");
return false;
}
return true;
}
4. 对比
4.1 AOP
(1) 跟spring aop基本一样,都提供之前、之后、异常处理能力。
(2) 从处理流程上看,应该是 HandlerInterceptor -> aspect -> controller 处理过程,但二者之间还有HttpMessageConverter等中间处理逻辑,在请求完成阶段,响应结果HttpServletResponse已处理完毕,相对于aspect,对结果的影响已很弱。
4.2 过滤器
(1) 从技术框架来说,web过滤器属于java servlet 原生规范,spring 拦截器属于 spring。因此,拦截器可以很方便的获取IOC容器中的bean,而过滤器不行,或者说比较麻烦(该问题在采用@WebFilter注解后,基本解决)。
(2) 从处理流程看,拦截器靠后些,都是在controller之前,都适合做预处理、拦截等处理。
(3) 从业务相关度来说,spring 拦截器更接近业务,更适合做业务相关的拦截处理,而web过滤器更适合做一些与业务无关的处理逻辑。