您的位置:首页 > 编程语言 > Java开发

SpringMVC拦截器执行过程源码分析

2017-04-26 11:45 459 查看
查看博客:拦截器的基本使用

介绍

这篇博客我们可以知道,前端SpringMVC前端控制器的主要逻辑基本上都在doDispatch()方法里面。

分析

注意:

下面我要说的Handler是一个统称,一个处理器的统称,不是一个类。

实现Handler通常有下面几种方式:

1.实现Controller接口。重写handleRequest()方法
2.继承AbstractController抽象类。特殊功能:该抽象类能够限制哪儿些请求方式(POST,GET)能够访问该Handler。
2.实现HttpRequestHandler接口。重写handleRequest()方法
3.继承MultiActionController。可以在一个类里面写多个方法。
- 方法要求,必须有两个参数。第一个为:HttpServletRequest,第二个为:HttpServletResponse,注意:有顺序要求!!!
- 方法名不能为handleRequest。
- 对返回值没有要求。你可以返回ModelAndView类型,也可以是void。


在doDispatch()中,该方法
mappedHandler=getHandler(processedRequest)
不仅仅是返回一个Handler对象,其实它是返回一个包含目标Handler和拦截器集合的一个包装类型对象。



进入getHandler(processedRequest)方法。



看看HandlerExecutionChain里面到底装了什么。



嗯,没错,里面装了Handler和拦截器,其中每次添加拦截器时,用的是interceptorList这个List对象。

当要获取HandlerExecutionChain里面的拦截器来使用时,就会用到interceptor数组。



我们已经知道,SpringMVC遍历HandlerMapping对象是为了获取到一个HandlerExecutionChain。而我们配置的对象是一个Handler而不是HandlerExecutionChain(Handler和HandlerExecutionChain是两个不同继承树里面的类),所以SpringMVC一定会创建一个HandlerExecutionChain对象,并且返回。



嗯,没错,就是这样。已经返回HandlerExecutionChain了。

在HandlerExecutionChain里面仅有两个构造方法:

两个构造方法非常有趣。



这两个构造方法合起来的意思是:

当我们创建HandlerExecutionChain时,传入的不是一个HandlerExecutionChain对象时,我们默认是不会加入拦截器的,但是我们会加入处理器映射器里面配置的拦截器。

如果我们传入的是一个HandlerExecutionChain对象时,就会加入该对象已有的拦截器,并且也会加入处理器映射器里面的拦截器。

所以啊!我们配置Handler的时候,该Handler也可以是一个HandlerExecutionChain对象。我们可以向HandlerExecutionChain里面注入Handler和拦截器集合,注入时必须注入到interceptors数组变量里面,而不是interceptorList里面,因为interceptorList会被重新在构造方法里面赋值。

实践:通过HandlerExecutionChain对象替代Handler,实现一个Handler拥有专属的拦截器组

创建Handler:

public class ItemController_Interceptor02 implements Controller{

@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {

System.out.println("执行ItemController_Interceptor02!!!");

return null;
}

}


创建拦截器:

public class Interceptor02 implements HandlerInterceptor{

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {

System.out.println("preHandler-----Interceptor02");

return true;
}

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

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

}


在SpringMVC核心配置文件中进行配置:

<!-- #######################创建HandlerExecutionChain对象,并向里面注入Handler和拦截器组##################### -->

<!-- 配置处理器 -->
<bean id="itemContorllerHandler01" class="cn.domarvel.controller.ItemController_Interceptor02"></bean>
<!-- 配置拦截器 -->
<bean id="interceptor02" class="cn.domarvel.interceptor.Interceptor02"></bean>

<bean id="handerExecutionChain01" class="org.springframework.web.servlet.HandlerExecutionChain">
<!-- 注入Handler,必须注入,如果为null,那么在寻找Adaptor的时候会找不到Adaptor来执行该Handler,会抛出异常!! -->
<property name="handler" ref="itemContorllerHandler01"></property>
<!-- 注入拦截器,拦截器可有可不有 -->
<property name="interceptors" ref="interceptor02"/>
</bean>

<!-- 配置处理器映射器 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/handlerExecutionChain-handler.action">handerExecutionChain01</prop>
</props>
</property>
</bean>

<!-- ############################################################################################## -->


注意:handler必须要注入到HandlerExecutionChain对象里面,否则。。。会抛出异常!!



嗯,感觉挺好的!!但是。。。。

哦豁!!报异常了。。。



那么这种方式是不对的。不能通过无参构造创建HandlerExecutionChai对象,之后再注入参数。

那么我们是否可以继承HandlerExecutionChain,把set方法和无参构造方法添加上呢??





也就是说,我们SpringMVC核心配置文件有变!!

<!-- #######################创建HandlerExecutionChain对象,并向里面注入Handler和拦截器组##################### -->

<!-- 配置处理器 -->
<bean id="itemContorllerHandler01" class="cn.domarvel.controller.ItemController_Interceptor02"></bean>
<!-- 配置拦截器 -->
<bean id="interceptor02" class="cn.domarvel.interceptor.Interceptor02"></bean>

<bean id="handerExecutionChain01" class="org.springframework.web.servlet.HandlerExecutionChain">
<!-- 注入Handler,必须注入,如果为null,那么在寻找Adaptor的时候会找不到Adaptor来执行该Handler,会抛出异常!! -->
<constructor-arg name="handler" ref="itemContorllerHandler01"></constructor-arg>
<!-- 注入拦截器,拦截器可有可不有 -->
<constructor-arg name="interceptors">
<array>
<ref bean="interceptor02"/>
</array>
</constructor-arg>
</bean>

<!-- 配置处理器映射器 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/handlerExecutionChain-handler.action">handerExecutionChain01</prop>
</props>
</property>
</bean>

<!-- ############################################################################################## -->


再来尝试访问下:



注意点:

当Handler(处理器)被HandlerExecutionChain替代时。拦截器组的组成由两个部分的拦截器组成。

总的拦截器=HandlerExecutionChain中的拦截器组+处理器映射器里面配置的拦截器。

前提条件:该HandlerExecutionChain对象被配置在该处理器映射器中。

HandlerExecutionChain中拦截器组的存储顺序为,先存储HandlerExecutionChain中的拦截器组,然后才是存储处理器映射器里面配置的拦截器。

嗯,非常Nice!!

继续之前之前之前的分析,目前我们讲到了这里:



当SpringMVC返回一个HandlerExecutionChain对象后。



进入applyPreHandle()方法:



在所有拦截器的applyPreHandle()方法执行完毕后,执行Handler,并且返回一个视图。

拦截器的preHandle()方法一般用来判断请求状态是否满足需要,编码是否需要调整等。



Handler执行完毕后执行postHandle()方法。该方法一般用作处理编码或者判断ModelAndView的结果是否正确,是否还需要调整。



执行所有拦截器的postHandle()方法后执行processDispatchResult()方法。





其中ModelAndView渲染的意思是,解析View,取出Model数据填充到request中,最后进行页面跳转(转发或者包含)。也就是说render()方法执行完毕后,我们客户端(浏览器)就能看到效果了。

render()方法由视图解析器实现。解析器在SpringMVC配置文件中进行配置。

最后的最后执行所有拦截器afterCompletion()方法。该步骤一般是用来释放资源用的。



至此拦截器的执行过程就讲解完毕了。

非常Nice!!!

实现拦截器的其它方法

继承HandlerInterceptorAdapter这个抽象类。该抽象类已经实现了HandlerInterceptor这个接口。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: