首先,这个Sevlet并不直接继承自HttpServlet,而是继承自FrameworkServlet类。不必惊讶这个类最终还是集成自HttpServlet,一些需要重写的方法也在一层层的继承中,封装了一遍又一遍。
此时需要了解一个前提,springMVC附着于spring之上,我们无法撇开spring单纯地写出一个和springMVC一模一样的框架来,我们能做的只是了解springMVC的处理过程,用自己的方式进行模拟。
DispatcherServlet做为调度总指挥,一些数据的初始化时必不可少的,这一节,我们开始了解DispatcherServlet数据初始化过程。我们把眼光放在这段代码上
- /**
- * This implementation calls {@link #initStrategies}.
- */
- @Override
- protected void onRefresh(ApplicationContext context) {
- initStrategies(context);
- }
- /**
- * Initialize the strategy objects that this servlet uses.
- * <p>May be overridden in subclasses in order to initialize further strategy objects.
- */
- protected void initStrategies(ApplicationContext context) {
- initMultipartResolver(context);
- initLocaleResolver(context);
- initThemeResolver(context);
- initHandlerMappings(context);
- initHandlerAdapters(context);
- initHandlerExceptionResolvers(context);
- initRequestToViewNameTranslator(context);
- initViewResolvers(context);
- initFlashMapManager(context);
- }
- /**
- * Template method which can be overridden to add servlet-specific refresh work.
- * Called after successful context refresh.
- * <p>This implementation is empty.
- * @param context the current WebApplicationContext
- * @see #refresh()
- */
- protected void onRefresh(ApplicationContext context) {
- // For subclasses: do nothing by default.
- }
- HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
- /**
- * Return a handler and any interceptors for this request. The choice may be made
- * on request URL, session state, or any factor the implementing class chooses.
- * <p>The returned HandlerExecutionChain contains a handler Object, rather than
- * even a tag interface, so that handlers are not constrained in any way.
- * For example, a HandlerAdapter could be written to allow another framework's
- * handler objects to be used.
- * <p>Returns {@code null} if no match was found. This is not an error.
- * The DispatcherServlet will query all registered HandlerMapping beans to find
- * a match, and only decide there is an error if none can find a handler.
- * @param request current HTTP request
- * @return a HandlerExecutionChain instance containing handler object and
- * any interceptors, or {@code null} if no mapping found
- * @throws Exception if there is an internal error
- */
- HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
最主要的内容是两个成员变量:
- private final Object handler;
- private HandlerInterceptor[] interceptors;
重点看三个方法:
- boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response)
- void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv)
- void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
- if (getInterceptors() != null) {
- for (int i = 0; i < getInterceptors().length; i++) {
- HandlerInterceptor interceptor = getInterceptors()[i];
- if (!interceptor.preHandle(request, response, this.handler)) {
- triggerAfterCompletion(request, response, null);
- return false;
- }
- this.interceptorIndex = i;
- }
- }
- return true;
不要问我所谓的拦截器栈,栈在哪里,人家压根就没用stack,就用了个数组模拟了一下,不信?看吧:这是 applyPostHanler的代码:
- for (int i = getInterceptors().length - 1; i >= 0; i--) {
- HandlerInterceptor interceptor = getInterceptors()[i];
- interceptor.postHandle(request, response, this.handler, mv);
- }
至于getHandler(request)内部到底怎么实现,我只能说,底层实现进过了层层封装,要贴代码也贴不过来了,只要知道getHandler()方法首先通过lookupHandler()方法(url匹配)从spring上下文中获得了一个handler对象,再通过getHandlerExecutionChain(handler, request)装填了匹配的interceptor,封装成一个HandlerExecutionChain返回。知道了大概意思,我们就能自己实现了。
另一个方法:initHandlerAdapters():首先我们想来看看这个HandlerAdapter是什么,查看其源代码,可以发现,这是一个接口,被许多个类实现了,留意其中的AbstractHandlerMethodAdapter类(注意AnnotationMethodHandlerAdapter在3.2版本后已经过期!),这是一个抽象类,拥有子类RequestMappingHandlerAdapter,这才是我们关注的重点。其中的关键方法为:
- private ModelAndView invokeHandleMethod(HttpServletRequest request,
- HttpServletResponse response, HandlerMethod handlerMethod)
至此,我想我们可以得出这样的结论:DispatcherServlet在初始化数据时无非再做两件事:
1.加载了一些HandlerMapping。
2.加载了一些HandlerAdapte。
前者包含了一个可以获得执行模块链(包括了拦截器和handler本身)的方法,后者包含了一个确实地执行hanlder并返回modelAndView的方法。有人可能会注意到我的用词“一些”,为什么是一些,现在还不是回答这个问题的时候。另一个需要注意的点是HandlerMapping和HandlerAdapte在数据初始化的过程中并没有执行。现在把眼光放回到我们的项目中来,有没有觉得springMVC其实并没有初始化一堆interceptor,也没有初始化一堆controller,为什么?因为人家压根就没必要啊,这些东西都在IOC容器中实例化好了,要用的时候通过HandlerMapping拿出来就好了。我们显然没有IOC容器,我们只能自己手动初始化这些数据。
思考一下我们到底该如何初始化。我们不一定要照搬springMVC的方式,我们可以在初始化时便将请求的URL和handler一一匹配,存放在map中,方便到时候取用。而拦截器没有固定的URL映射,我们可以先全部加载出来,在请求到来时再进行匹配