这一段时间一直在看关于算法部分的书籍,所以始终没来的及更新自己的博客。之前就已经看完了Spring MVC的全部文章,今天就更新完我的关于Spring源码学习的最后一篇文章。
1.大体流程
上次说到了关于handler(也就是Controller层对象的获取),那么服务器是根据用户请求的url来进行确认访问某一个HandlerMapping取出其中的handler对象以及相应的拦截器链,但是这个请求的分发处理,之前的内容并没有提及。从书上可以了解到是通过DispatcherServlet的doService方法进行实现的。
doDispatch(request, response);
这个方法中的doDispatch是分发请求的入口。
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
这两个对象一个表示发送的请求,一个表示拦截器链,这个拦截器链和之后和handler绑定到一起的拦截器链是有关系的。
mappedHandler = getHandler(processedRequest);
然后引入了一个我们很熟悉的对象,ModelAndView对象,将有这个对象来持有handler处理请求的结果。
ModelAndView mv = null;
在实际调用handler的时候,要使用HandlerAdapter检查一下handler的合法性,生成一个HandlerAdapter的对象ha
通过调用HandlerAdapter的handle方法,实际上触发对Controller的handleRequest方法的调用。通俗一点,就是我们在声明的RequestMapping的方法下写的那些代码的执行。将处理的结果保存在ModelAndView对象中
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
然后调用render()方法将mv对象进行展现。从中我们大致了解了整个的流程。
现在我们来具体的讲解一下里面的一些细节
2.handler对象的获取
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
原理和之前的博客写的比较类似,也是从注册完成的handlerMappings中查到的。
还有关于getHandlerAdapter()方法
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
这个也是为了保证handler对象要是Controller接口的实现。
3.Spring MVC视图的呈现
这个视图的呈现交给了render方法进行处理
首先对传入的ModelAndView对象进行解析并获取的视图对象
View view;
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
在view对象配置完毕后,调用view对象的render方法,这个方法是由它的子类AbstractView进行实现的,从书上的描述中我们不难发现例如jsp页面的具体渲染是由我们配置的服务器来完成的。View对象只是包含了jsp的名字以及需要显示的一些数据,就像我们用jstl表示的数据一样。这些数据保存在model中。
4.总结
关于Spring源码的学习,对于我目前的学习水平而言就要告一段落了。Spring的扩展功能很多,也绝对不只是我看到的书上的这些,通过对于Spring的依赖注入,AOP,事务处理以及Spring MVC的学习。我可以清楚地感觉到,这个框架所体现出的依赖注入以及控制反转思想,我们将我们需要的bean写在xml中。由Spring生成一个生命周期为服务器运行周期内的一个ApplicationContext容器进行统一的管理。增强了我们代码的解耦性,在生成对象的时候我们才会真正为决定这个对象所依赖的其他对象,这使得对象的声明看其来更加明了。我们不需要为一个具有多种嵌套依赖可能性的类声明多次,只需要声明一个最原始的模板,将它所依赖的对象由接口表示。在真正调用的时候通过依赖注入的方式进行实例化,这使得我们的代码更加灵活。
通过对Spring源码的阅读,原本神秘的Spring其实和我们日常写的代码是相同的,只是整个框架对于健壮性以及高并发等要点进行了充分的完善。源码的解析并不神秘,当然只是看一遍这本书,其中的很多细节都没有展示出来,我只是了解了大概的流程。但是这本书对我的帮助是巨大的,这也体现了面向接口的编程思想,每一层只对它的上层负责,它所需要的功能实现则由它的下一级接口进行统一的实现。
单纯地对这本书进行查看还不足以完全地了解Spring,如果你有兴趣,可以试着自己手写一下关于Spring的整个实现过程。当然有书籍进行帮助,书名为《Spring专业开发指南》,有兴趣者可以进行查看。