spring(2) spring ioc容器在Web容器中的启动

上面我们分析了IOC容器本身的实现,下面我们看看在典型的web环境中,Spring IOC容器是怎样被载入和起作用的。
简单的说,在web容器中,通过ServletContext为Spring的IOC容器提供宿主环境,对应的建立起一个IOC容器的体系。其中,首先需要建立的是根上下文,这个上下文持有的对象可以有业务对象,数据存取对象,资源,事物管理器等各种中间层对象。在这个上下文的基础上,和web MVC相关还会有一个上下文来保存控制器之类的MVC对象,这样就构成了一个层次化的上下文结构。在web容器中启动Spring应用程序就是一个建立这个上下文体系的过程。Spring为web应用提供了上下文的扩展接口
WebApplicationContext:

Java代码

  1. publicinterface WebApplicationContextextends ApplicationContext {
  2. //这里定义的常量用于在ServletContext中存取根上下文
  3. String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
  4. ……
  5. //对WebApplicationContext来说,需要得到Web容器的ServletContext
  6. ServletContext getServletContext();
  7. }
public interface WebApplicationContext extends ApplicationContext { //这里定义的常量用于在ServletContext中存取根上下文 String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT"; ...... //对WebApplicationContext来说,需要得到Web容器的ServletContext ServletContext getServletContext(); }

而一般的启动过程,Spring会使用一个默认的实现,XmlWebApplicationContext – 这个上下文实现作为在web容器中的根上下文容器被建立起来,具体的建立过程在下面我们会详细分析。

Java代码

  1. publicclass XmlWebApplicationContextextends AbstractRefreshableWebApplicationContext {
  2. /** 这是和web部署相关的位置信息,用来作为默认的根上下文bean定义信息的存放位置*/
  3. publicstaticfinal String DEFAULT_CONFIG_LOCATION ="/WEB-INF/applicationContext.xml";
  4. publicstaticfinal String DEFAULT_CONFIG_LOCATION_PREFIX ="/WEB-INF/";
  5. publicstaticfinal String DEFAULT_CONFIG_LOCATION_SUFFIX =".xml";
  6. //我们又看到了熟悉的loadBeanDefinition,就像我们前面对IOC容器的分析中一样,这个加载工程在容器的refresh()的时候启动。
  7. protectedvoid loadBeanDefinitions(DefaultListableBeanFactory beanFactory)throws IOException {
  8. //对于XmlWebApplicationContext,当然使用的是XmlBeanDefinitionReader来对bean定义信息来进行解析
  9. XmlBeanDefinitionReader beanDefinitionReader =new XmlBeanDefinitionReader(beanFactory);
  10. beanDefinitionReader.setResourceLoader(this);
  11. beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
  12. initBeanDefinitionReader(beanDefinitionReader);
  13. loadBeanDefinitions(beanDefinitionReader);
  14. }
  15. protectedvoid initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {
  16. }
  17. //使用XmlBeanDefinitionReader来读入bean定义信息
  18. protectedvoid loadBeanDefinitions(XmlBeanDefinitionReader reader)throws BeansException, IOException {
  19. String[] configLocations = getConfigLocations();
  20. if (configLocations !=null) {
  21. for (int i = 0; i < configLocations.length; i++) {
  22. reader.loadBeanDefinitions(configLocations[i]);
  23. }
  24. }
  25. }
  26. //这里取得bean定义信息位置,默认的地方是/WEB-INF/applicationContext.xml
  27. protected String[] getDefaultConfigLocations() {
  28. if (getNamespace() !=null) {
  29. returnnew String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
  30. }
  31. else {
  32. returnnew String[] {DEFAULT_CONFIG_LOCATION};
  33. }
  34. }
  35. }
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext { /** 这是和web部署相关的位置信息,用来作为默认的根上下文bean定义信息的存放位置*/ public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml"; public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/"; public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml"; //我们又看到了熟悉的loadBeanDefinition,就像我们前面对IOC容器的分析中一样,这个加载工程在容器的refresh()的时候启动。 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { //对于XmlWebApplicationContext,当然使用的是XmlBeanDefinitionReader来对bean定义信息来进行解析 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) { } //使用XmlBeanDefinitionReader来读入bean定义信息 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { String[] configLocations = getConfigLocations(); if (configLocations != null) { for (int i = 0; i < configLocations.length; i++) { reader.loadBeanDefinitions(configLocations[i]); } } } //这里取得bean定义信息位置,默认的地方是/WEB-INF/applicationContext.xml protected String[] getDefaultConfigLocations() { if (getNamespace() != null) { return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX}; } else { return new String[] {DEFAULT_CONFIG_LOCATION}; } } }

对于一个Spring激活的web应用程序,可以通过使用Spring代码声明式的指定在web应用程序启动时载入应用程序上下文(WebApplicationContext),Spring的ContextLoader是提供这样性能的类,我们可以使用 ContextLoaderServlet或者ContextLoaderListener的启动时载入的Servlet来实例化Spring IOC容器 – 为什么会有两个不同的类来装载它呢,这是因为它们的使用需要区别不同的Servlet容器支持的Serlvet版本。但不管是 ContextLoaderSevlet还是 ContextLoaderListener都使用ContextLoader来完成实际的WebApplicationContext的初始化工作。这个ContextLoder就像是Spring Web应用程序在Web容器中的加载器booter。当然这些Servlet的具体使用我们都要借助web容器中的部署描述符来进行相关的定义。
下面我们使用ContextLoaderListener作为载入器作一个详细的分析,这个Servlet的监听器是根上下文被载入的地方,也是整个 Spring web应用加载上下文的第一个地方;从加载过程我们可以看到,首先从Servlet事件中得到ServletContext,然后可以读到配置好的在web.xml的中的各个属性值,然后ContextLoder实例化WebApplicationContext并完成其载入和初始化作为根上下文。当这个根上下文被载入后,它被绑定到web应用程序的ServletContext上。任何需要访问该ApplicationContext的应用程序代码都可以从WebApplicationContextUtils类的静态方法来得到:

Java代码

  1. WebApplicationContext getWebApplicationContext(ServletContext sc)
WebApplicationContext getWebApplicationContext(ServletContext sc)

以Tomcat作为Servlet容器为例,下面是具体的步骤:
1.Tomcat 启动时需要从web.xml中读取启动参数,在web.xml中我们需要对ContextLoaderListener进行配置,对于在web应用启动入口是在ContextLoaderListener中的初始化部分;从Spring MVC上看,实际上在web容器中维护了一系列的IOC容器,其中在ContextLoader中载入的IOC容器作为根上下文而存在于 ServletContext中。

Java代码

  1. //这里对根上下文进行初始化。
  2. publicvoid contextInitialized(ServletContextEvent event) {
  3. //这里创建需要的ContextLoader
  4. this.contextLoader = createContextLoader();
  5. //这里使用ContextLoader对根上下文进行载入和初始化
  6. this.contextLoader.initWebApplicationContext(event.getServletContext());
  7. }
//这里对根上下文进行初始化。 public void contextInitialized(ServletContextEvent event) { //这里创建需要的ContextLoader this.contextLoader = createContextLoader(); //这里使用ContextLoader对根上下文进行载入和初始化 this.contextLoader.initWebApplicationContext(event.getServletContext()); }

通过ContextLoader建立起根上下文的过程,我们可以在ContextLoader中看到:

Java代码

  1. public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
  2. throws IllegalStateException, BeansException {
  3. //这里先看看是不是已经在ServletContext中存在上下文,如果有说明前面已经被载入过,或者是配置文件有错误。
  4. if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
  5. //直接抛出异常
  6. ………
  7. }
  8. ……………
  9. try {
  10. // 这里载入根上下文的父上下文
  11. ApplicationContext parent = loadParentContext(servletContext);
  12. //这里创建根上下文作为整个应用的上下文同时把它存到ServletContext中去,注意这里使用的ServletContext的属性值是
  13. //ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,以后的应用都是根据这个属性值来取得根上下文的 - 往往作为自己上下文的父上下文
  14. this.context = createWebApplicationContext(servletContext, parent);
  15. servletContext.setAttribute(
  16. WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,this.context);
  17. ……….
  18. returnthis.context;
  19. }
  20. …………
  21. }
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) throws IllegalStateException, BeansException { //这里先看看是不是已经在ServletContext中存在上下文,如果有说明前面已经被载入过,或者是配置文件有错误。 if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { //直接抛出异常 ......... } ............... try { // 这里载入根上下文的父上下文 ApplicationContext parent = loadParentContext(servletContext); //这里创建根上下文作为整个应用的上下文同时把它存到ServletContext中去,注意这里使用的ServletContext的属性值是 //ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,以后的应用都是根据这个属性值来取得根上下文的 - 往往作为自己上下文的父上下文 this.context = createWebApplicationContext(servletContext, parent); servletContext.setAttribute( WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); .......... return this.context; } ............ }

建立根上下文的父上下文使用的是下面的代码,取决于在web.xml中定义的参数:locatorFactorySelector,这是一个可选参数:

Java代码

  1. protected ApplicationContext loadParentContext(ServletContext servletContext)
  2. throws BeansException {
  3. ApplicationContext parentContext = null;
  4. String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM);
  5. String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM);
  6. if (locatorFactorySelector !=null) {
  7. BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);
  8. ……..
  9. //得到根上下文的父上下文的引用
  10. this.parentContextRef = locator.useBeanFactory(parentContextKey);
  11. //这里建立得到根上下文的父上下文
  12. parentContext = (ApplicationContext)this.parentContextRef.getFactory();
  13. }
  14. return parentContext;
  15. }
protected ApplicationContext loadParentContext(ServletContext servletContext) throws BeansException { ApplicationContext parentContext = null; String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM); String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM); if (locatorFactorySelector != null) { BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector); ........ //得到根上下文的父上下文的引用 this.parentContextRef = locator.useBeanFactory(parentContextKey); //这里建立得到根上下文的父上下文 parentContext = (ApplicationContext) this.parentContextRef.getFactory(); } return parentContext; }

得到根上下文的父上下文以后,就是根上下文的创建过程:

Java代码

  1. protected WebApplicationContext createWebApplicationContext(
  2. ServletContext servletContext, ApplicationContext parent)throws BeansException {
  3. //这里需要确定我们载入的根WebApplication的类型,由在web.xml中配置的contextClass中配置的参数可以决定我们需要载入什么样的ApplicationContext,
  4. //如果没有使用默认的。
  5. Class contextClass = determineContextClass(servletContext);
  6. ………
  7. //这里就是上下文的创建过程
  8. ConfigurableWebApplicationContext wac =
  9. (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
  10. //这里保持对父上下文和ServletContext的引用到根上下文中
  11. wac.setParent(parent);
  12. wac.setServletContext(servletContext);
  13. //这里从web.xml中取得相关的初始化参数
  14. String configLocation = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);
  15. if (configLocation !=null) {
  16. wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation,
  17. ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));
  18. }
  19. //这里对WebApplicationContext进行初始化,我们又看到了熟悉的refresh调用。
  20. wac.refresh();
  21. return wac;
  22. }
protected WebApplicationContext createWebApplicationContext( ServletContext servletContext, ApplicationContext parent) throws BeansException { //这里需要确定我们载入的根WebApplication的类型,由在web.xml中配置的contextClass中配置的参数可以决定我们需要载入什么样的ApplicationContext, //如果没有使用默认的。 Class contextClass = determineContextClass(servletContext); ......... //这里就是上下文的创建过程 ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); //这里保持对父上下文和ServletContext的引用到根上下文中 wac.setParent(parent); wac.setServletContext(servletContext); //这里从web.xml中取得相关的初始化参数 String configLocation = servletContext.getInitParameter(CONFIG_LOCATION_PARAM); if (configLocation != null) { wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation, ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS)); } //这里对WebApplicationContext进行初始化,我们又看到了熟悉的refresh调用。 wac.refresh(); return wac; }

初始化根ApplicationContext后将其存储到SevletContext中去以后,这样就建立了一个全局的关于整个应用的上下文。这个根上下文会被以后的DispatcherServlet初始化自己的时候作为自己ApplicationContext的父上下文。这个在对 DispatcherServlet做分析的时候我们可以看看到。

3.完成对ContextLoaderListener的初始化以后, Tomcat开始初始化DispatchServlet,- 还记得我们在web.xml中队载入次序进行了定义。DispatcherServlet会建立自己的ApplicationContext,同时建立这个自己的上下文的时候会从ServletContext中得到根上下文作为父上下文,然后再对自己的上下文进行初始化,并最后存到 ServletContext中去供以后检索和使用。
可以从DispatchServlet的父类FrameworkServlet的代码中看到大致的初始化过程,整个ApplicationContext的创建过程和ContextLoder创建的过程相类似:

Java代码

  1. protectedfinalvoid initServletBean()throws ServletException, BeansException {
  2. ………
  3. try {
  4. //这里是对上下文的初始化过程。
  5. this.webApplicationContext = initWebApplicationContext();
  6. //在完成对上下文的初始化过程结束后,根据bean配置信息建立MVC框架的各个主要元素
  7. initFrameworkServlet();
  8. }
  9. ……..
  10. }
protected final void initServletBean() throws ServletException, BeansException { ......... try { //这里是对上下文的初始化过程。 this.webApplicationContext = initWebApplicationContext(); //在完成对上下文的初始化过程结束后,根据bean配置信息建立MVC框架的各个主要元素 initFrameworkServlet(); } ........ }

对initWebApplicationContext()调用的代码如下:

Java代码

  1. protected WebApplicationContext initWebApplicationContext()throws BeansException {
  2. //这里调用WebApplicationContextUtils静态类来得到根上下文
  3. WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
  4. //创建当前DispatcherServlet的上下文,其上下文种类使用默认的在FrameworkServlet定义好的:DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
  5. WebApplicationContext wac = createWebApplicationContext(parent);
  6. ……..
  7. if (isPublishContext()) {
  8. //把当前建立的上下文存到ServletContext中去,注意使用的属性名是和当前Servlet名相关的。
  9. String attrName = getServletContextAttributeName();
  10. getServletContext().setAttribute(attrName, wac);
  11. }
  12. return wac;
  13. }
protected WebApplicationContext initWebApplicationContext() throws BeansException { //这里调用WebApplicationContextUtils静态类来得到根上下文 WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); //创建当前DispatcherServlet的上下文,其上下文种类使用默认的在FrameworkServlet定义好的:DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class; WebApplicationContext wac = createWebApplicationContext(parent); ........ if (isPublishContext()) { //把当前建立的上下文存到ServletContext中去,注意使用的属性名是和当前Servlet名相关的。 String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); } return wac; }

其中我们看到调用了WebApplicationContextUtils的静态方法得到根ApplicationContext:

Java代码

  1. publicstatic WebApplicationContext getWebApplicationContext(ServletContext sc) {
  2. //很简单,直接从ServletContext中通过属性名得到根上下文
  3. Object attr = sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
  4. …….
  5. return (WebApplicationContext) attr;
  6. }
  7. 然后创建DispatcherServlet自己的WebApplicationContext:
  8. protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent)
  9. throws BeansException {
  10. …….
  11. //这里使用了BeanUtils直接得到WebApplicationContext,ContextClass是前面定义好的DEFAULT_CONTEXT_CLASS =
  12. //XmlWebApplicationContext.class;
  13. ConfigurableWebApplicationContext wac =
  14. (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(getContextClass());
  15. //这里配置父上下文,就是在ContextLoader中建立的根上下文
  16. wac.setParent(parent);
  17. //保留ServletContext的引用和相关的配置信息。
  18. wac.setServletContext(getServletContext());
  19. wac.setServletConfig(getServletConfig());
  20. wac.setNamespace(getNamespace());
  21. //这里得到ApplicationContext配置文件的位置
  22. if (getContextConfigLocation() !=null) {
  23. wac.setConfigLocations(
  24. StringUtils.tokenizeToStringArray(
  25. getContextConfigLocation(), ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));
  26. }
  27. //这里调用ApplicationContext的初始化过程,同样需要使用refresh()
  28. wac.refresh();
  29. return wac;
  30. }
public static WebApplicationContext getWebApplicationContext(ServletContext sc) { //很简单,直接从ServletContext中通过属性名得到根上下文 Object attr = sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); ....... return (WebApplicationContext) attr; } 然后创建DispatcherServlet自己的WebApplicationContext: protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) throws BeansException { ....... //这里使用了BeanUtils直接得到WebApplicationContext,ContextClass是前面定义好的DEFAULT_CONTEXT_CLASS = //XmlWebApplicationContext.class; ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(getContextClass()); //这里配置父上下文,就是在ContextLoader中建立的根上下文 wac.setParent(parent); //保留ServletContext的引用和相关的配置信息。 wac.setServletContext(getServletContext()); wac.setServletConfig(getServletConfig()); wac.setNamespace(getNamespace()); //这里得到ApplicationContext配置文件的位置 if (getContextConfigLocation() != null) { wac.setConfigLocations( StringUtils.tokenizeToStringArray( getContextConfigLocation(), ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS)); } //这里调用ApplicationContext的初始化过程,同样需要使用refresh() wac.refresh(); return wac; }

4. 然后就是DispatchServlet中对Spring MVC的配置过程,首先对配置文件中的定义元素进行配置 – 请注意这个时候我们的WebApplicationContext已经建立起来了,也意味着DispatcherServlet有自己的定义资源,可以需要从web.xml中读取bean的配置信息,通常我们会使用单独的xml文件来配置MVC中各个要素定义,这里和web容器相关的加载过程实际上已经完成了,下面的处理和普通的Spring应用程序的编写没有什么太大的差别,我们先看看MVC的初始化过程:

Java代码

  1. protectedvoid initFrameworkServlet()throws ServletException, BeansException {
  2. initMultipartResolver();
  3. initLocaleResolver();
  4. initThemeResolver();
  5. initHandlerMappings();
  6. initHandlerAdapters();
  7. initHandlerExceptionResolvers();
  8. initRequestToViewNameTranslator();
  9. initViewResolvers();
  10. }
protected void initFrameworkServlet() throws ServletException, BeansException { initMultipartResolver(); initLocaleResolver(); initThemeResolver(); initHandlerMappings(); initHandlerAdapters(); initHandlerExceptionResolvers(); initRequestToViewNameTranslator(); initViewResolvers(); }

5. 这样MVC的框架就建立起来了,DispatchServlet对接受到的HTTP Request进行分发处理由doService()完成,具体的MVC处理过程我们在doDispatch()中完成,其中包括使用Command模式建立执行链,显示模型数据等,这些处理我们都可以在DispatcherServlet的代码中看到:

Java代码

  1. protectedvoid doService(HttpServletRequest request, HttpServletResponse response)throws Exception {
  2. ……
  3. try {
  4. doDispatch(request, response);
  5. }
  6. …….
  7. }
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { ...... try { doDispatch(request, response); } ....... }

实际的请求分发由doDispatch(request,response)来完成:

Java代码

  1. protectedvoid doDispatch(final HttpServletRequest request, HttpServletResponse response)throws Exception {
  2. …….
  3. // 这是Spring定义的执行链,里面放了映射关系对应的handler和定义的相关拦截器。
  4. HandlerExecutionChain mappedHandler = null;
  5. ……
  6. try {
  7. //我们熟悉的ModelAndView在这里出现了。
  8. ModelAndView mv = null;
  9. try {
  10. processedRequest = checkMultipart(request);
  11. //这里更具request中的参数和映射关系定义决定使用的handler
  12. mappedHandler = getHandler(processedRequest,false);
  13. ……
  14. //这里是handler的调用过程,类似于Command模式中的execute.
  15. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
  16. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  17. …….
  18. //这里将模型数据通过视图进行展现
  19. if (mv !=null && !mv.wasCleared()) {
  20. render(mv, processedRequest, response);
  21. }
  22. ……..
  23. }
protected void doDispatch(final HttpServletRequest request, HttpServletResponse response) throws Exception { ....... // 这是Spring定义的执行链,里面放了映射关系对应的handler和定义的相关拦截器。 HandlerExecutionChain mappedHandler = null; ...... try { //我们熟悉的ModelAndView在这里出现了。 ModelAndView mv = null; try { processedRequest = checkMultipart(request); //这里更具request中的参数和映射关系定义决定使用的handler mappedHandler = getHandler(processedRequest, false); ...... //这里是handler的调用过程,类似于Command模式中的execute. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); ....... //这里将模型数据通过视图进行展现 if (mv != null && !mv.wasCleared()) { render(mv, processedRequest, response); } ........ }

这样具体的MVC模型的实现就由bean配置文件里定义好的view resolver,handler这些类来实现用户代码的功能。
总结上面的过程,我们看到在web容器中,ServletContext可以持有一系列的web上下文,而在整个web上下文中存在一个根上下文来作为其它 Servlet上下文的父上下文。这个根上下文是由ContextLoader载入并进行初始化的,对于我们的web应用, DispatcherSerlvet载入并初始化自己的上下文,这个上下文的父上下文是根上下文,并且我们也能从ServletContext中根据 Servlet的名字来检索到我们需要的对应于这个Servlet的上下文,但是根上下文的名字是由Spring唯一确定的。这个 DispactcherServlet建立的上下文就是我们开发Spring MVC应用的IOC容器。
具体的web请求处理在上下文体系建立完成以后由DispactcherServlet来完成,上面对MVC的运作做了一个大致的描述,下面我们会具体就SpringMVC的框架实现作一个详细的分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值