过滤器跟拦截器的区别
spring mvc的拦截器是只拦截controller而不拦截jsp,html 页面文件的。这就用到过滤器filter了,filter是在servlet前执行的,你也可以理解成过滤器中包含拦截器,一个请求过来 ,先进行过滤器处理,看程序是否受理该请求 。 过滤器放过后 , 程序中的拦截器进行处理 。
1、拦截器不依赖servlet容器,过滤器依赖;
2、拦截器是基于java反射机制来实现的,过滤器基于回调
过滤器:关注web请求;
拦截器:关注方法调用;
Spring拦截器分类
spring中拦截器主要分两种,一个是HandlerInterceptor,一个是MethodInterceptor。
HandlerInterceptor
HandlerInterceptor是springMVC项目中的拦截器,它拦截的目标是请求的地址,比MethodInterceptor先执行。
HandlerInterceptor拦截的是请求地址,所以针对请求地址做一些验证、预处理等操作比较合适。当你需要统计请求的响应时间时MethodInterceptor将不太容易做到,因为它可能跨越很多方法或者只涉及到已经定义好的方法中一部分代码。
实现一个HandlerInterceptor拦截器可以直接实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter类。
看下UML:
HandlerInterceptorAdapter.class
public abstract class HandlerInterceptorAdapter implementsAsyncHandlerInterceptor {publicHandlerInterceptorAdapter() {
}
//在业务处理器处理请求之前被调用public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throwsException {return true;
}
//在业务处理器处理请求完成之后,生成视图之前执行public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throwsException {
}
// 在DispatcherServlet完全处理完请求之后被调用,可用于清理资源public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throwsException {
}public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throwsException {
}
}
执行顺序如图:
具体体现在 DispatcherServlet.class doDispatch() 方法中,看下源码:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throwsException {
HttpServletRequest processedRequest=request;
HandlerExecutionChain mappedHandler= null;boolean multipartRequestParsed = false;
WebAsyncManager asyncManager=WebAsyncUtils.getAsyncManager(request);try{try{
ModelAndView mv= null;
Object dispatchException= null;try{
processedRequest= this.checkMultipart(request);
multipartRequestParsed= processedRequest !=request;
mappedHandler= this.getHandler(processedRequest);if (mappedHandler == null) {this.noHandlerFound(processedRequest, response);return;
}
HandlerAdapter ha= this.getHandlerAdapter(mappedHandler.getHandler());
String method=request.getMethod();boolean isGet = "GET".equals(method);if (isGet || "HEAD".equals(method)) {long lastModified =ha.getLastModified(request, mappedHandler.getHandler());if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) &&isGet) {return;
}
}if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;
}
mv=ha.handle(processedRequest, response, mappedHandler.getHandler());if(asyncManager.isConcurrentHandlingStarted()) {return;
}this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}catch(Exception var20) {
dispatchException=var20;
}catch(Throwable var21) {
dispatchException= new NestedServletException("Handler dispatch failed", var21);
}this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
}catch(Exception var22) {this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
}catch(Throwable var23) {this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
}finally{if(asyncManager.isConcurrentHandlingStarted()) {if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}else if(multipartRequestParsed) {this.cleanupMultipart(processedRequest);
}
}
}
现在需要一个简单的demo,深入了解几个方法:
importorg.springframework.web.servlet.handler.HandlerInterceptorAdapter;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjavax.servlet.http.HttpSession;public class SecurityInterceptor extendsHandlerInterceptorAdapter {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throwsException {
System.out.println("SecurityInterceptor >>>>>>>>1");return true;
}
}
importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.InterceptorRegistration;importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configurationpublic class WebSecurityConfig extendsWebMvcConfigurationSupport {
@BeanpublicSecurityInterceptor getSecurityInterceptor() {return newSecurityInterceptor();
}
@Overridepublic voidaddInterceptors(InterceptorRegistry registry) {
InterceptorRegistration addInterceptor=registry.addInterceptor(getSecurityInterceptor());//排除配置
addInterceptor.excludePathPatterns("/403");
addInterceptor.excludePathPatterns("/toLogin");
addInterceptor.excludePathPatterns("/login**");//拦截配置
addInterceptor.addPathPatterns("/**");
}
}
启动工程(springboot工程):
请求:http://localhost:8080/toLogin ,因为配置了排除设置,后台无打印。
请求:http://localhost:8080/userInfo/userAdd,后台有打印。
发散:如果是多个拦截器,他们preHandle、postHandle、afterCompletion方法执行顺序是什么?
看下demo:
importorg.springframework.lang.Nullable;importorg.springframework.web.servlet.ModelAndView;importorg.springframework.web.servlet.handler.HandlerInterceptorAdapter;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjavax.servlet.http.HttpSession;public class SecurityInterceptor extendsHandlerInterceptorAdapter {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throwsException {
System.out.println("SecurityInterceptor.preHandle >>>>>>>>1");return true;
}public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throwsException {
System.out.println("SecurityInterceptor.postHandle >>>>>>>>1");
}public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throwsException {
System.out.println("SecurityInterceptor.afterCompletion >>>>>>>>1");
}
}
importorg.springframework.lang.Nullable;importorg.springframework.web.servlet.ModelAndView;importorg.springframework.web.servlet.handler.HandlerInterceptorAdapter;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;public class HelloInterceptor extendsHandlerInterceptorAdapter {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throwsException {
System.out.println("HelloInterceptor.preHandle >>>>>>>>3");return true;
}public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throwsException {
System.out.println("HelloInterceptor.postHandle >>>>>>>>3");
}public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throwsException {
System.out.println("HelloInterceptor.afterCompletion >>>>>>>>3");
}
}
importorg.springframework.lang.Nullable;importorg.springframework.web.servlet.ModelAndView;importorg.springframework.web.servlet.handler.HandlerInterceptorAdapter;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;public class RoleAuthorizationInterceptor extendsHandlerInterceptorAdapter {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throwsException {
System.out.println("RoleAuthorizationInterceptor.preHandle >>>>>>>>2");return true;
}public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throwsException {
System.out.println("RoleAuthorizationInterceptor.postHandle >>>>>>>>2");
}public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throwsException {
System.out.println("RoleAuthorizationInterceptor.afterCompletion >>>>>>>>2");
}
}
importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.InterceptorRegistration;importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configurationpublic class WebSecurityConfig extendsWebMvcConfigurationSupport {
@BeanpublicSecurityInterceptor getSecurityInterceptor() {return newSecurityInterceptor();
}
@BeanpublicHelloInterceptor getHelloInterceptor() {return newHelloInterceptor();
}
@BeanpublicRoleAuthorizationInterceptor getRoleAuthorizationInterceptor() {return newRoleAuthorizationInterceptor();
}
@Overridepublic voidaddInterceptors(InterceptorRegistry registry) {
InterceptorRegistration addInterceptor=registry.addInterceptor(getSecurityInterceptor());//排除配置
addInterceptor.excludePathPatterns("/403");
addInterceptor.excludePathPatterns("/toLogin");
addInterceptor.excludePathPatterns("/login**");//拦截配置
addInterceptor.addPathPatterns("/**");
InterceptorRegistration roleInter=registry.addInterceptor(getRoleAuthorizationInterceptor());//拦截配置
roleInter.addPathPatterns("/**");
InterceptorRegistration helloInter=registry.addInterceptor(getHelloInterceptor());
helloInter.addPathPatterns("/**");
}
}
执行结果:
如果拦截器的preHandle()返回false,结果会怎样,改下demo:
WebSecurityConfig.java
@Overridepublic voidaddInterceptors(InterceptorRegistry registry) {
InterceptorRegistration addInterceptor=registry.addInterceptor(getSecurityInterceptor());//排除配置
/*addInterceptor.excludePathPatterns("/403");
addInterceptor.excludePathPatterns("/toLogin");
addInterceptor.excludePathPatterns("/login**");*/
//拦截配置
addInterceptor.addPathPatterns("/**");
InterceptorRegistration roleInter=registry.addInterceptor(getRoleAuthorizationInterceptor());//拦截配置
roleInter.addPathPatterns("/**");
InterceptorRegistration helloInter=registry.addInterceptor(getHelloInterceptor());
helloInter.addPathPatterns("/**");
}
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throwsException {
System.out.println("RoleAuthorizationInterceptor.preHandle >>>>>>>>2");return false;
}
其他不变,运行结果:
通过源码分析,当prehandle返回false,则执行triggerAfterCompletion()执行拦截器的afterCompletion()方法。
if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;
}
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throwsException {
HandlerInterceptor[] interceptors= this.getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor=interceptors[i];if (!interceptor.preHandle(request, response, this.handler)) {this.triggerAfterCompletion(request, response, (Exception)null);return false;
}
}
}return true;
}
如果preHandle都返回true,postHandle()异常,又会是什么情况呢?
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throwsException {
System.out.println("RoleAuthorizationInterceptor.postHandle >>>>>>>>2");throw newNullPointerException();
}
结果:
结论:
1、如果多个拦截器,执行顺序:preHandle() :123 ,postHandle():321,afterCompletion():321
2、preHandle() 返回false,不会往下执行
3、preHandle()返回true的拦截器,必然会执行他的afterCompletion();
4、如果preHandle()都返回true,有一个拦截器的postHandle()抛出异常,则后面拦截器的postHandle()不会执行。(注意:写代码时要注意)
参考:
https://www.cnblogs.com/niceyoo/p/8735637.html