SpringMVC架构及源码分析
来源:互联网 发布:盲打软件 编辑:程序博客网 时间:2024/06/17 09:14
SpringMVC
本文在基于SpringMVC 4.3.2.RELEASE版本基础上,对源码进行分析,并探讨SpringMVC的原理及用法。
springMVC
整体架构
在了解Spring整体架构时,这里盗用开涛博客的一张图。
对该架构流程进行简单的分析如下:
任何一个请求都要经过DispatcherServlet进行分发,DispatcherServlet并不对请求进行处理,而是将请求交给HandlerMapping进行映射;HandlerMapping将请求映射为HandlerExecutionChain对象。该对象包含一个Handler对象和多个HandlerInterceptor对象。这里就体现了一种责任链模式的思想;Handler经过一层包装后变成HandlerAdapter,从而支持多种类型的处理器(Controller),HandlerAdapter将请求交给具体的处理器进行处理,完成后返回ModelAndView;通过ViewResolver对视图进行解析,并利用Model数据模型对视图渲染(Render).
DispatcherServlet1
DispatcherServlet继承关系如下:
DispatcherServlet—>FrameworkServlet—>HttpServletBean—>HttpServlet—>GenericServlet—>Servlet.
HttpServletBean继承自javax.servlet.http包下的HttpServlet,那么就先从该类分析:
/** * Simple extension of {@link javax.servlet.http.HttpServlet} which treats * its config parameters ({@code init-param} entries within the * {@code servlet} tag in {@code web.xml}) as bean properties. * * <p>A handy superclass for any type of servlet. Type conversion of config * parameters is automatic, with the corresponding setter method getting * invoked with the converted value. It is also possible for subclasses to * specify required properties. Parameters without matching bean property * setter will simply be ignored. * * <p>This servlet leaves request handling to subclasses, inheriting the default * behavior of HttpServlet ({@code doGet}, {@code doPost}, etc). * * <p>This generic servlet base class has no dependency on the Spring * {@link org.springframework.context.ApplicationContext} concept. Simple * servlets usually don't load their own context but rather access service * beans from the Spring root application context, accessible via the * filter's {@link #getServletContext() ServletContext} (see * {@link org.springframework.web.context.support.WebApplicationContextUtils}). * * <p>The {@link FrameworkServlet} class is a more specific servlet base * class which loads its own application context. FrameworkServlet serves * as direct base class of Spring's full-fledged {@link DispatcherServlet}. * * @author Rod Johnson * @author Juergen Hoeller * @see #addRequiredProperty * @see #initServletBean * @see #doGet * @see #doPost */@SuppressWarnings("serial")public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware { }
该类的初始化方法init()
/** * Map config parameters onto bean properties of this servlet, and * invoke subclass initialization. * @throws ServletException if bean properties are invalid (or required * properties are missing), or if subclass initialization fails. */ @Override public final void init() throws ServletException { if (logger.isDebugEnabled()) { logger.debug("Initializing servlet '" + getServletName() + "'"); } // Set bean properties from init parameters. try { PropertyValues pvs = new ServletConfigPropertyValues( getServletConfig(), this.requiredProperties); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); initBeanWrapper(bw); bw.setPropertyValues(pvs, true); } catch (BeansException ex) { logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); throw ex; } // Let subclasses do whatever initialization they like. initServletBean(); if (logger.isDebugEnabled()) { logger.debug("Servlet '" + getServletName() + "' configured successfully"); } }
try…catch中的内容暂时略过。
之后,该方法调用了initServletBean(),该方法在类中进行声明,但并没有实现,而是留给子类FrameworkServlet实现。子类FrameworkServlet实现过程如下:
/** * Overridden method of {@link HttpServletBean}, invoked after any bean properties * have been set. Creates this servlet's WebApplicationContext. */ @Override protected final void initServletBean() throws ServletException { getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'"); if (this.logger.isInfoEnabled()) { this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started"); } long startTime = System.currentTimeMillis(); try { this.webApplicationContext = initWebApplicationContext(); initFrameworkServlet(); } catch (ServletException ex) { this.logger.error("Context initialization failed", ex); throw ex; } catch (RuntimeException ex) { this.logger.error("Context initialization failed", ex); throw ex; } if (this.logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " + elapsedTime + " ms"); } }
该方法中依然调用了initFrameworkServlet(),该方法在类中定义,并没有实现,而是留给子类进行实现,不过这次DispatcherServlet并没有重写该方法。
/** * This method will be invoked after any bean properties have been set and * the WebApplicationContext has been loaded. The default implementation is empty; * subclasses may override this method to perform any initialization they require. * @throws ServletException in case of an initialization exception */ protected void initFrameworkServlet() throws ServletException { }
如上对DispatcherServlet对请求处理的过程分析,可以看出,DispatcherServlet将请求分发给HandlerMapping.
HandlerMapping是位于org.springframework.web.servlet包下的接口.他就定义了一个函数getHandler(HttpServletRequest request).
/** * 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;
ContextLoaderListener初始化上下文和DispatcherServlet初始化上下文的关系
DispatcherServlet中有几个特殊的Bean,这些Bean就是上文中提到的Controller, HandlerMapping, HandlerAdapter, ViewResolver, LocalResolver, ThemeResolver, MultipartResolver.
DispatcherServlet需要在web.xml中进行配置。需要声明其在容器启动时初始化,即load-on-startup。同时设置其url-pattern为“/”,表示它拦截所有的请求。
它默认使用WebApplicationContext作为上下文,如果不进行配置,默认会去/WEB-INF/[servlet名字]-servlet.xml中寻找对应的配置文件。
也可以手动对其进行配置,以覆盖默认的配置。
- https://fangjian0423.gitbooks.io/springmvc-source-minibook/content/SpringMVC-dispatcherServlet.html
[^2]:https://my.oschina.net/lichhao/blog/99039 ↩
- SpringMVC架构及源码分析
- tomcat架构及源码分析
- libvirt架构及源码分析
- libvirt架构及源码分析
- libvirt架构及源码分析
- springMVC工作原理及源码分析
- SpringMVC 启动流程及相关源码分析
- SpringMVC DispatcherServlet执行流程及源码分析
- springmvc架构原理分析
- SpringMVC源码分析,springMVC原理
- springMVC源码分析--DispatcherServlet请求获取及处理
- springMVC源码分析--@ModelAttribute使用及运行原理
- springMVC源码分析--DispatcherServlet请求获取及处理
- springMVC源码分析--DispatcherServlet请求获取及处理
- springMVC源码分析--DispatcherServlet请求获取及处理
- springMVC源码分析--DispatcherServlet请求获取及处理
- springMVC源码分析--DispatcherServlet请求获取及处理
- SpringMVC源码分析系列
- 2017 年初、阿里、腾讯、百度、华为、京东、搜狗和滴滴面试题汇集
- AOJ800开关灯问题
- 面试中排序算法问题
- Spring框架体系简介
- bat文件实现修改IP和DNS
- SpringMVC架构及源码分析
- bug处理情况填表
- 第十一次笔记
- sql知识,不定时更新
- 打印两个有序链表的公共部分
- network
- Python ast 学习笔记1–手动建ast
- ArcEngine要素闪烁
- HDOJ_1008电梯上的时间(Elevator)