Spring源码学习笔记(2)

Spring源码学习笔记(二)

  前言----

       最近花了些时间看了《Spring源码深度解析》这本书,算是入门了Spring的源码吧。打算写下系列文章,回忆一下书的内容,总结代码的运行流程。推荐那些和我一样没接触过SSH框架源码又想学习的,阅读郝佳编著的《Spring源码深度解析》这本书,会是个很好的入门。


 

    SpringMVC 的的入口就是 DispatcherServlet , 也是主要逻辑实现的地方。  先看看 DispatcherServlet 的 继承关系。

    

    可以看出 DispatcherServlet 也应该有和普通 Servlet 同样的逻辑方法, 即 doDelete(), doGet(), doPost(), doPut() 以及 init(), destory() 等方法。


DispatcherServlet的初始化

   初始化是调用 Servlet 的 init() 方法。

    public final void init() throws ServletException {

        try {
            // 第一步: init-param的封装
            PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
            //第二步: 封装为 BeanWrapper 类,Spring可以把 获取的 init-param 属性注入
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            //第三步: 针对 Resource 属性 注册属性编辑器
            ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
            this.initBeanWrapper(bw);
            //第四步: 添加属性
            bw.setPropertyValues(pvs, true);
        } catch (BeansException var4) {
            this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);
            throw var4;
        }
        // 第五步: 子类扩展
        this.initServletBean();

    }

    在 init() 方法 第一步中, 封装 初始化 参数, 找到一个内部类, 逻辑放在了构造函数中, 一段简单清晰的代码, 来一波!!! d=====( ̄▽ ̄*)b 

    private static class ServletConfigPropertyValues extends MutablePropertyValues {
        public ServletConfigPropertyValues(ServletConfig config, Set<String> requiredProperties) throws ServletException {
            // 第一步:  根据需要的属性, 生成迭代器, 并填充
            Set<String> missingProps = requiredProperties != null && !requiredProperties.isEmpty()?new HashSet(requiredProperties):null;
            Enumeration en = config.getInitParameterNames();

            while(en.hasMoreElements()) {
                String property = (String)en.nextElement();
                Object value = config.getInitParameter(property);
                this.addPropertyValue(new PropertyValue(property, value));
                //第二步:  填充的属性要移出集合
                if(missingProps != null) {
                    missingProps.remove(property);
                }
            }
            //第三步: 遍历完后还有未填充属性, 需要抛异常  
            if(missingProps != null && missingProps.size() > 0) {
                throw new ServletException("Initialization from ServletConfig for servlet '" + config.getServletName() + "' failed; the following required properties were missing: " + StringUtils.collectionToDelimitedString(missingProps, ", "));
            }
        }
    }

    在 init()方法 第四步中, 注入的属性包括 contextAttribute, contextClass, nameSpace, contextConfigLocation 等属性, 

    在 init()方法 第五步中, 父类 FrameworkServlet 定义了 initServletBean() 方法。 初始化了 ServletBean 。

    protected final void initServletBean() throws ServletException {
        
        long startTime = System.currentTimeMillis();

        try {
            //第一步:  去掉日志, 忽略时间,剩下这句
            this.webApplicationContext = this.initWebApplicationContext();
            this.initFrameworkServlet();
        }

        if(this.logger.isInfoEnabled()) {
            long elapsedTime = System.currentTimeMillis() - startTime;
            this.logger.info("FrameworkServlet '" + this.getServletName() + "': initialization completed in " + elapsedTime + " ms");
        }

    }

 


 

    

    在 initServletBean() 方法中, 只有 创建或刷新 WebApplicationContext 实例的方法。

 1     protected WebApplicationContext initWebApplicationContext() {
 2         //第一步:  获取context实例
 3         WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
 4         WebApplicationContext wac = null;
 5         if(this.webApplicationContext != null) {
 6             //第二步:  判断已在构造函数中注入
 7             wac = this.webApplicationContext;
 8             if(wac instanceof ConfigurableWebApplicationContext) {
 9                 ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;
10                 if(!cwac.isActive()) {
11                     if(cwac.getParent() == null) {
12                         cwac.setParent(rootContext);
13                     }
14 
15                     //第三步:  刷新上下文  
16                     this.configureAndRefreshWebApplicationContext(cwac);
17                 }
18             }
19         }
20         //第四步:  根据contextAttribute 属性创建 context
21         if(wac == null) {
22             wac = this.findWebApplicationContext();
23         }
24         //第五步:  还是TMD 的木有, 重新创建一个
25         if(wac == null) {
26             wac = this.createWebApplicationContext(rootContext);
27         }
28         //第六步:  context不是一个支持刷新的ConfigurableWebApplicationContext 或 构造函数注入的context已经被刷新
29         if(!this.refreshEventReceived) {
30             this.onRefresh(wac);
31         }
32         //第七步:  把context 实例 设置为 contextAttributes的属性
33         if(this.publishContext) {
34             String attrName = this.getServletContextAttributeName();
35             this.getServletContext().setAttribute(attrName, wac);
36             if(this.logger.isDebugEnabled()) {
37                 this.logger.debug("Published WebApplicationContext of servlet '" + this.getServletName() + "' as ServletContext attribute with name [" + attrName + "]");
38             }
39         }
40 
41         return wac;
42     }

    在 initWebApplicationContext() 方法中, 第四步通过 contextAttribute 查找 context, 其中 contextAttribute 属性在 web.xml 文件中配置,  默认为

WebApplicationContext.class.getName() + ".ROOT'。 

    protected WebApplicationContext findWebApplicationContext() {
        //第一步: 获取属性
        String attrName = this.getContextAttribute();
        if(attrName == null) {
            return null;
        } else {
            //第二步:  根据属性获取 context
            WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext(), attrName);
            if(wac == null) {
                throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");
            } else {
                return wac;
            }
        }
    } 

    在 initWebApplicationContext() 方法中, 若 判断 context 始终为null, 则 通过 createWebApplicationContext() 方法创建新的 context 实例。

1     protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
2         //往下调用方法
3         return this.createWebApplicationContext((ApplicationContext)parent);
4     }
 1     protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
 2         Class<?> contextClass = this.getContextClass();
 3         if(this.logger.isDebugEnabled()) {
 4             this.logger.debug("Servlet with name '" + this.getServletName() + "' will try to create custom WebApplicationContext context of class '" + contextClass.getName() + "'" + ", using parent context [" + parent + "]");
 5         }
 6 
 7         //第一步: 类型判断        
 8      if(!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
 9             throw new ApplicationContextException("Fatal initialization error in servlet with name '" + this.getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext");
10         } else {
11             //第二步:  反射创建 context
12             ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
13             //第三步:  为 context 设置属性
14             wac.setEnvironment(this.getEnvironment());
15             //第四步: parent 为在ContextLoaderListener初始化时的 WebApplicationContext 实例
16             wac.setParent(parent);
17             wac.setConfigLocation(this.getContextConfigLocation());
18             this.configureAndRefreshWebApplicationContext(wac);
19             return wac;
20         }
21     }

    在 initWebApplicationContext() 方法第三步中, 无论通过构造函数 还是 重新创建, 都会调用  this.configureAndRefreshWebApplicationContext(wac)  方法。 虽然看起来像给子类扩展的, 但是实际上 代码不可貌相啊。   ----------------\(^o^)/!!!

 1     protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
 2         //第一步:  为context 修改 id 
 3         if(ObjectUtils.identityToString(wac).equals(wac.getId())) {
 4             if(this.contextId != null) {
 5                 wac.setId(this.contextId);
 6             } else {
 7                 wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(this.getServletContext().getContextPath()) + "/" + this.getServletName());
 8             }
 9         }
10         //第二步: 为 context 填充属性
11         wac.setServletContext(this.getServletContext());
12         wac.setServletConfig(this.getServletConfig());
13         wac.setNamespace(this.getNamespace());
14         wac.addApplicationListener(new SourceFilteringListener(wac, new FrameworkServlet.ContextRefreshListener(null)));
15         ConfigurableEnvironment env = wac.getEnvironment();
16         if(env instanceof ConfigurableWebEnvironment) {
17             ((ConfigurableWebEnvironment)env).initPropertySources(this.getServletContext(), this.getServletConfig());
18         }
19 
20         this.postProcessWebApplicationContext(wac);
21         this.applyInitializers(wac);
22         //第三步: 整合parent 到 context
23         wac.refresh();
24     }

    在 initWebApplicationContext() 方法第六步中, 调用 onRefresh() 方法, 初始化 一大堆的 Spring 的 web 功能必须的全局变量。 截图感受下, 在DispatcherServlet 中,  o( ̄▽ ̄)d

    

    在 DispatcherServlet 中, 重写了父类 FrameworkServlet 的 onRefresh() 方法。

    //第一步:   没第一步
    protected void onRefresh(ApplicationContext context) {
        this.initStrategies(context);
    }

    protected void initStrategies(ApplicationContext context) {
        this.initMultipartResolver(context);
        this.initLocaleResolver(context);
        this.initThemeResolver(context);
        this.initHandlerMappings(context);
        this.initHandlerAdapters(context);
        this.initHandlerExceptionResolvers(context);
        this.initRequestToViewNameTranslator(context);
        this.initViewResolvers(context);
        this.initFlashMapManager(context);
    }

 


 

    介绍 DispatcherServlet 中的 全局变量的初始化工作, 打一个分隔行, 和上边的基本没什么关系了!!!    O(∩_∩)O加油!

 


 

强迫症, 再打一个。。。。

    (一)  初始化 MultipartResolver

     在 application-context.xml 文件中 配置一个 MutipartResolver 的Bean, 然后通过 Spring 容器去读取就行了!!!

 1     private void initMultipartResolver(ApplicationContext context) {
 2         try {
 3             //第一步:  读取 bean
 4             this.multipartResolver = (MultipartResolver)context.getBean("multipartResolver", MultipartResolver.class);
 5             if(this.logger.isDebugEnabled()) {
 6                 this.logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
 7             }
 8         } catch (NoSuchBeanDefinitionException var3) {
 9             this.multipartResolver = null;
10             if(this.logger.isDebugEnabled()) {
11                 this.logger.debug("Unable to locate MultipartResolver with name 'multipartResolver': no multipart request handling provided");
12             }
13         }
14 
15     }

    (二)  初始化 LocaleResolver

    和 MutipartResolver 差不多, 读取 xml 文件中配置的 bean, 但是 LocaleResolver 可以基于 URL, Session,  Cookie来配置, 且有默认值。

 1     private void initLocaleResolver(ApplicationContext context) {
 2         try {
 3             //第一步:  读取配置的 bean
 4             this.localeResolver = (LocaleResolver)context.getBean("localeResolver", LocaleResolver.class);
 5             if(this.logger.isDebugEnabled()) {
 6                 this.logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
 7             }
 8         } catch (NoSuchBeanDefinitionException var3) {
 9             //第二步:  生成默认对象
10             this.localeResolver = (LocaleResolver)this.getDefaultStrategy(context, LocaleResolver.class);
11             if(this.logger.isDebugEnabled()) {
12                 this.logger.debug("Unable to locate LocaleResolver with name 'localeResolver': using default [" + this.localeResolver + "]");
13             }
14         }
15 
16     }

    (三)  初始化 ThemeResolver 

      与 LocaleResolver 相同, 都有默认的 对象。

 1     private void initThemeResolver(ApplicationContext context) {
 2         try {
 3             //第一步:  读取bean
 4             this.themeResolver = (ThemeResolver)context.getBean("themeResolver", ThemeResolver.class);
 5             if(this.logger.isDebugEnabled()) {
 6                 this.logger.debug("Using ThemeResolver [" + this.themeResolver + "]");
 7             }
 8         } catch (NoSuchBeanDefinitionException var3) {
 9             //第二步:  生成默认对象
10             this.themeResolver = (ThemeResolver)this.getDefaultStrategy(context, ThemeResolver.class);
11             if(this.logger.isDebugEnabled()) {
12                 this.logger.debug("Unable to locate ThemeResolver with name 'themeResolver': using default [" + this.themeResolver + "]");
13             }
14         }
15 
16     }

    (四)  初始化 HandlerMappings

     此处有套路!!!

 1    private void initHandlerMappings(ApplicationContext context) {
 2         this.handlerMappings = null;
 3         if(this.detectAllHandlerMappings) {
 4             //第一步:  获取所有 HandlerMapping 类型的类 
 5             Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
 6             if(!matchingBeans.isEmpty()) {
 7                 this.handlerMappings = new ArrayList(matchingBeans.values());
 8                 //第二步:  排序所有的 HandlerMapping
 9                 OrderComparator.sort(this.handlerMappings);
10             }
11         } else {
12             try {
13                 //第三步:  获取指定的 HandlerMapping,  返回一个 SingletonList
14                 HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
15                 this.handlerMappings = Collections.singletonList(hm);
16             } catch (NoSuchBeanDefinitionException var3) {
17                 ;
18             }
19         }
20     
21         if(this.handlerMappings == null) {
22             //第四步:  生成默认的 HandlerMapping
23             this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
24             if(this.logger.isDebugEnabled()) {
25                 this.logger.debug("No HandlerMappings found in servlet '" + this.getServletName() + "': using default");
26             }
27         }
28 
29     }

    在 initHandlerMappings() 第四步中, 生成默认的 HandlerMapping 是通过读取文件套路方法获取的。

    (五)  初始化 HandlerAdapters

    也是使用模板套路方法, 和 HandlerMappings 相同。

 1     private void initHandlerAdapters(ApplicationContext context) {
 2         this.handlerAdapters = null;
 3         if(this.detectAllHandlerAdapters) {
 4             //第一步:  获取所有的 HandlerAdapter 类型的类
 5             Map<String, HandlerAdapter> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
 6             if(!matchingBeans.isEmpty()) {
 7                 this.handlerAdapters = new ArrayList(matchingBeans.values());
 8                 //第二步:  排序所有的 HandlerAdapter
 9                 OrderComparator.sort(this.handlerAdapters);
10             }
11         } else {
12             try {
13                 //第三步:  获取指定的 HandlerAdapter 
14                 HandlerAdapter ha = (HandlerAdapter)context.getBean("handlerAdapter", HandlerAdapter.class);
15                 this.handlerAdapters = Collections.singletonList(ha);
16             } catch (NoSuchBeanDefinitionException var3) {
17                 ;
18             }
19         }
20 
21         if(this.handlerAdapters == null) {
22             //第四步:  生成默认的  HandlerAdapter
23             this.handlerAdapters = this.getDefaultStrategies(context, HandlerAdapter.class);
24             if(this.logger.isDebugEnabled()) {
25                 this.logger.debug("No HandlerAdapters found in servlet '" + this.getServletName() + "': using default");
26             }
27         }
28 
29     }    

    在 initHandlerMappings() 第四步中  以及 在 initHandlerAdapters()的第四步中,  getDefaultStrategies()  方法读取 配置文件的 属性。

 1     protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
 2         String key = strategyInterface.getName();
 3         //第一步: 尝试从 defaultStrategies 中加载 属性
 4         String value = defaultStrategies.getProperty(key);
 5         if(value == null) {
 6             return new LinkedList();
 7         } else {
 8             String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
 9             List<T> strategies = new ArrayList(classNames.length);
10             String[] var7 = classNames;
11             int var8 = classNames.length;
12 
13             for(int var9 = 0; var9 < var8; ++var9) {
14                 String className = var7[var9];
15 
16                 try {
17                     //第二步:  根据属性对应的值,反射创建类实例
18                     Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
19                     Object strategy = this.createDefaultStrategy(context, clazz);
20                     strategies.add(strategy);
21                 }
22             }
23 
24             return strategies;
25         }
26     }

    defaultStategies 在类初始化时加载了配置文件, 封装了 属性。

1     static {
2         try {
3             //第一步:  加载配置文件
4             ClassPathResource resource = new ClassPathResource("DispatcherServlet.properties", DispatcherServlet.class);
5             defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
6         } catch (IOException var1) {
7             throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + var1.getMessage());
8         }
9     }

    一起瞄一下配置文件, 也就是 DispatcherServlet.properties 的内容。

 1 org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
 2 
 3 org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
 4 
 5 org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
 6     org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
 7 
 8 org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
 9     org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
10     org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
11 
12 org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
13     org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
14     org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
15 
16 org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
17 
18 org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
19 
20 org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

    也就是在 properties 文件中, 定义了许多变量默认的类型, 若未定义, 则从 properties 文件中读取对应的信息。

    (六)  初始化 HandlerExceptionResolvers

    和谁都不一样, 不知道怎么解释, 上代码吧, 简单易懂

 1     private void initHandlerExceptionResolvers(ApplicationContext context) {
 2         this.handlerExceptionResolvers = null;
 3         //第一步:  获取所有的 HandlerExceptionResolver 类型的类
 4         if(this.detectAllHandlerExceptionResolvers) {
 5             Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
 6             if(!matchingBeans.isEmpty()) {
 7                 this.handlerExceptionResolvers = new ArrayList(matchingBeans.values());
 8                 //第二步:  排序所有的 HandlerExceptionResolver
 9                 OrderComparator.sort(this.handlerExceptionResolvers);
10             }
11         } else {
12             try {
13                 //第三步:  获取指定的 HandlerExceptionResolver
14                 HandlerExceptionResolver her = (HandlerExceptionResolver)context.getBean("handlerExceptionResolver", HandlerExceptionResolver.class);
15                 this.handlerExceptionResolvers = Collections.singletonList(her);
16             } catch (NoSuchBeanDefinitionException var3) {
17                 ;
18             }
19         }
20          //第四步:  生成默认的对象
21        if(this.handlerExceptionResolvers == null) {
22               this.handlerExceptionResolvers = this.getDefaultStrategies(context, HandlerExceptionResolver.class);
23               if(this.logger.isDebugEnabled()) {
24                 this.logger.debug("No HandlerExceptionResolvers found in servlet '" + this.getServletName() + "': using default");
25             }
26         }
27 
28     }

 

      (七)  初始化 RequestToViewNameTranslator

      此处省略解释, 反正你也不听!

 1     private void initRequestToViewNameTranslator(ApplicationContext context) {
 2         try {
 3             //第一步:  读取 xml 中定义的 bean
 4             this.viewNameTranslator = (RequestToViewNameTranslator)context.getBean("viewNameTranslator", RequestToViewNameTranslator.class);
 5             if(this.logger.isDebugEnabled()) {
 6                 this.logger.debug("Using RequestToViewNameTranslator [" + this.viewNameTranslator + "]");
 7             }
 8         } catch (NoSuchBeanDefinitionException var3) {
 9             //第二步:  生成默认的 RequestToViewNameTranslator
10             this.viewNameTranslator = (RequestToViewNameTranslator)this.getDefaultStrategy(context, RequestToViewNameTranslator.class);
11             if(this.logger.isDebugEnabled()) {
12                 this.logger.debug("Unable to locate RequestToViewNameTranslator with name 'viewNameTranslator': using default [" + this.viewNameTranslator + "]");
13             }
14         }
15 
16     }

 

     (八)  初始化 ViewResolvers

    不听不听我不听!!

 1     private void initViewResolvers(ApplicationContext context) {
 2         this.viewResolvers = null;
 3         if(this.detectAllViewResolvers) {
 4             //第一步:  获取所有的 ViewResolver 类型的 bean
 5             Map<String, ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
 6             if(!matchingBeans.isEmpty()) {
 7                 this.viewResolvers = new ArrayList(matchingBeans.values());
 8                 //第二步:  排序所有的  ViewResolver
 9                 OrderComparator.sort(this.viewResolvers);
10             }
11         } else {
12             try {
13                 //第三步:  获取指定的 ViewResolver 
14                 ViewResolver vr = (ViewResolver)context.getBean("viewResolver", ViewResolver.class);
15                 this.viewResolvers = Collections.singletonList(vr);
16             } catch (NoSuchBeanDefinitionException var3) {
17                 ;
18             }
19         }
20         //第四步:  生成默认的 ViewResolver 
21         if(this.viewResolvers == null) {
22             this.viewResolvers = this.getDefaultStrategies(context, ViewResolver.class);
23             if(this.logger.isDebugEnabled()) {
24                 this.logger.debug("No ViewResolvers found in servlet '" + this.getServletName() + "': using default");
25             }
26         }
27 
28     }

 

     (九)  初始化 FlashMapManager

       FlashMapManager 属性了解得比较少。 简单地说就是在重定向的时候保存属性, 使重定向之后还能使用。 FlashMapManager 管理 FlashMap, FlashMap 保存了 flash attributes。

 1    private void initFlashMapManager(ApplicationContext context) {
 2         try {
 3             //第一步:   读取 xml 配置的 bean
 4             this.flashMapManager = (FlashMapManager)context.getBean("flashMapManager", FlashMapManager.class);
 5             if(this.logger.isDebugEnabled()) {
 6                 this.logger.debug("Using FlashMapManager [" + this.flashMapManager + "]");
 7             }
 8         } catch (NoSuchBeanDefinitionException var3) {
 9             //第二步:  生成默认的 FlashMapManager
10             this.flashMapManager = (FlashMapManager)this.getDefaultStrategy(context, FlashMapManager.class);
11             if(this.logger.isDebugEnabled()) {
12                 this.logger.debug("Unable to locate FlashMapManager with name 'flashMapManager': using default [" + this.flashMapManager + "]");
13             }
14         }
15 
16     }

 

 


 

    

    到此, DispatcherServlet 的初始化工作, 也就是 init() 方法结束, 接下来就是像平常使用 Servlet 一样, 进行 service(),  doGet(), doPost()  等方法的处理逻辑了。    <( ̄︶ ̄)>

 

posted @ 2017-04-06 16:38  VimKeyLin  阅读(299)  评论(0编辑  收藏  举报