SpringMvc拦截器HandlerInterceptor

简介:

拦截器intercprot  和 过滤器 Filter 其实作用类似,可应用于:
1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
2、权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;
3、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间。

自定义拦截器实现 HandlerInterceptor 接口,也可以继承HandlerInterceptorAdapter。 实现接口需要实现对应的3中方法,继承父类只需要实现需要的方法即可。

HandlerInterceptor 接口:

public interface HandlerInterceptor {

    /**
     * preHandle方法是进行处理器拦截用的,顾名思义,该方法将在Controller处理之前进行调用,
     * SpringMVC中的Interceptor拦截器是链式的,可以同时存在多个Interceptor,
     * 然后SpringMVC会根据声明的前后顺序一个接一个的执行,
     * 而且所有的Interceptor中的preHandle方法都会在Controller方法调用之前调用。
     * SpringMVC的这种Interceptor链式结构也是可以进行中断的,
     * 这种中断方式是令preHandle的返回值为false,当preHandle的返回值为false的时候整个请求就结束了。
     */
    boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception;

    /**
     * postHandle是进行处理器拦截用的,它的执行在Controller的方法调用之后执行,但是它会在DispatcherServlet进行视图的渲染之前执行,
     * 也就是说在这个方法中你可以对ModelAndView进行操作。这个方法的链式结构跟正常访问的方向是相反的,
     * 也就是说先声明的Interceptor拦截器该方法反而会后调用。
     */
    void postHandle(
            HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception;

    /**
     * 该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。
     * 该方法将在整个请求完成之后,也就是DispatcherServlet渲染了视图执行, 这个方法的主要作用是用于清理资源的,
     */
    void afterCompletion(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception;

}

图例:

SpringMvc拦截器HandlerInterceptor_第1张图片SpringMvc拦截器HandlerInterceptor_第2张图片SpringMvc拦截器HandlerInterceptor_第3张图片SpringMvc拦截器HandlerInterceptor_第4张图片

 通过也四张图可以看出:

1、如果一个拦截器的preHandle返回true,则该拦截器的afterCompletion方法一定会被调用。

 

源码分析:

public class DispatcherServlet extends FrameworkServlet{

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		Exception dispatchException = null;

		try {
				mappedHandler = getHandler(processedRequest);
				//调用preHandle方法
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					//如果有拦截器preHandle返回false,程序不在向下执行。
					return;
				}

				//调用controller中的方法
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				//调用postHandle方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			//处理程序调用的结果
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		
	}

	/**
	 * 处理程序调用的结果
	 */
	private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
		HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
		
		//渲染视图
		if (mv != null && !mv.wasCleared()) {
			render(mv, request, response);
		}
		//调用afterCompletion方法
		if (mappedHandler != null) {
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}
	   
}


public class HandlerExecutionChain {

	private final Object handler;
	private HandlerInterceptor[] interceptors;//拦截器数组
	private int interceptorIndex = -1;
	
	
	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HandlerInterceptor[] interceptors = getInterceptors();//获取拦截器数组
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = 0; i < interceptors.length; i++) {
				HandlerInterceptor interceptor = interceptors[i];
				if (!interceptor.preHandle(request, response, this.handler)) {//如果有拦截器preHandle返回false。
					//触发拦截器的afterCompletion方法。
					triggerAfterCompletion(request, response, null);
					//后面的拦截器preHandle将不再执行
					return false;
				}
				this.interceptorIndex = i;
			}
		}
		return true;
	}

	
	void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
		     //postHandle
			for (int i = interceptors.length - 1; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				interceptor.postHandle(request, response, this.handler, mv);
			}
		}
	}
	

	void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
			throws Exception {

		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = this.interceptorIndex; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				try {
					interceptor.afterCompletion(request, response, this.handler, ex);
				}
				catch (Throwable ex2) {
					logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
				}
			}
		}
	}
	
}

 

 filter和interceptor执行顺序:

 

SpringMvc拦截器HandlerInterceptor_第5张图片

过滤器和拦截器区别:

1、发生的时机不一样,filter是在servlet容器外,interceptor在servlet容器内,且可以对请求的3个关键步骤进行拦截处理。另外filter在过滤是只能对request和response进行操作,而interceptor可以对request、response、handler、modelAndView、exception进行操作。
2、拦截器不依赖与servlet容器,过滤器依赖与servlet容器
3、interceptor只能对action起作用,filter几乎对所有请求起作用。

 

测试用例:

 

@SpringBootApplication
@ServletComponentScan
@Controller
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }


    @RequestMapping("/abcd")
    @ResponseBody
    public String index() {
        System.out.println("helloWord");
        return "helloWord";
    }

}



@Order(1)
@WebFilter(urlPatterns = "/abcd/*",filterName = "myFilterOne")
class MyFilter1 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("filter1_start");
        long start=System.currentTimeMillis();
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("filter1_end_"+(System.currentTimeMillis()-start));
    }

    @Override
    public void destroy() {

    }
}


@Order(2)
@WebFilter(urlPatterns = "/abcd/*", filterName = "myFilterTwo")
 class MyFilter2 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("filter2_start");
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("filter2_end" );
    }

    @Override
    public void destroy() {

    }
}


class MyInterceptor1 implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("interceptor1_preHandle");
        request.setAttribute("start", System.currentTimeMillis());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("interceptor1_postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("interceptor1_afterCompletion_"+(System.currentTimeMillis()-(Long) request.getAttribute("start")));
    }
}

class MyInterceptor2 implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("interceptor2_preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("interceptor2_postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("interceptor2_afterCompletion");
    }
}


@Component
class MyInterceptorConfig extends WebMvcConfigurerAdapter {

    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/abcd/**");
        registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/abcd/**");
    }
}

结果:

SpringMvc拦截器HandlerInterceptor_第6张图片

你可能感兴趣的:(springMvc)