zoukankan      html  css  js  c++  java
  • spring源码学习之springMVC(一)

      个人感觉《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》这本书对spring的解读要优于《Spring源码深度解析(第2版)》这本书的,后者感觉就是再陈述一些代码,没有自己的理解,有点呆板!下面是《Spring技术内幕》中的springMVC的描述:

      在部署描述中,为这个DispatcherServlet定义了对应的URL映射,这些URL映射为这个servlet指定了需要处理的HTTP请求。context-param 参数的配置用来指定spring IoC容器读取Bean定义的XML文件的路径,作为springMVC启动类,ContextLoaderListener被定义一个监听器,这个监听器是与web服务器的生命周期相关联的,由ContextLoaderListener监听器负责完成IoC容器
      在web环境中的启动工作,DispatcherServlet和ContextLoaderListener提供了在web容器中对spring的接口,也就是说,这些接口与web容器耦合是通过ServletContext来实现的,这个ServletContext为spring的IoC容器体系提供了一个宿主环境,在宿主环境中,springMVC建立起一个IoC容器的体系。这个IoC容器体系是通过ContextLoaderListener初始化来建立起来的,在建立IoC容器的体系后,把DispatcherServlet作为spring MVC处理web请求的转发器建立起来,从而完成响应HTTP请求的准备,有了这些基本的配置,建立在IOC容器基础上的spring MVC就可以正常的发挥作用了。

    《Spring源码深度解析(第2版)》中的内容:

      spring框架提供了构建完整的Web应用程序的全功能MVC模块,通过策略接口,spring框架是高度可配置的,而且支持多种视图技术,springMVC框架并不知道使用的视图,
    所以不会强迫您只使用JSP技术,springMVC分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让他们更容易进行定制

    spring的NVC是基于Servlet功能实现的,通过实现servlet接口DispatcherServlet来封装其核心功能实现,通过将请求分配给程序处理,同时带有可配置的处理程序映射,
    视图解析、本地语言、主体解析以及下载文件支持。默认的处理程序是非常简单的Controller接口,只有一个方法ModelAndView handleRequest(request, response);
    spring提供了一个控制器层次结构,可以派生子类。

    springMVC解决的问题主要就是以下几点:
      将web页面的请求传给服务器
      根据不同的请求处理不同的逻辑单元
      返回处理结果数据并跳转至结果页面

    一、ContextLoaderListener

      对于springMVC功能实现的分析,我们首先从web.xml开始,在web.xml 文件中我们首先配置的就是ContextLoaderListener,那么它所提供的功能有哪些,又是
    如何实现的呢?
      当使用编程方式的时候我们可以直接将spring配置信息作为参数注入spring容器中,如ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    但是在web下,我们需要更多的是与web环境相互结合,通常的办法是将路径以context-param的方式注册并使用ContextLoaderListener进行监听读取
      ContextLoaderListener的作用就是启动web容器时,自动装配ApplicationContext的配置信息。因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,
    启动容器时,就会默认执行它实现的方法,使用ServletContextListener接口,开发者能够在为客户端请求提供服务之前向ServletContext中添加任意的对象,这个对象在
    ServletContext启动的时候被初始化,然后在ServletContext整个运行期间都是可用的
    每一个web应用都有一个ServletContext与之相关联。ServletContext对象在应用启动时被创建,在应用关闭的时候被销毁。ServletContext在全局范围内有效,
    类似于应用中的一个全局变量
      在ServletContextListener中核心逻辑便是初始化WebApplicationContext实例并存放至ServletContext中

    1、ServletContextListener的使用
    (1)创建自定义的ServletContextListener
    首先我们创建ServletContextListener,目标是在系统启动时添加自定义属性,以便于在全局范围内可以随时调用。系统启动的时候会调用ServletContextListener实现类的
    contextInitialized方法,所以需要实现在这个方法中实现我们的初始化逻辑。

     1 public class MyDataContextListener implements ServletContextListener{
     2     private ServletContext context = null;
     3     public MyDataContextListener(){
     4         
     5     }
     6     // 该方法在ServletContext启动之后调用,并准备好处理客户端请求
     7     public void contextInitialized (SevrvletContextEvent event){
     8         this.context = event.getServletContext();
     9         // 实现自己的逻辑并将结果记录在属性中
    10         context = setAttribute("myData","this is myData");
    11     }
    12     // 这个方法在ServletContext关闭时调用
    13     public void contextDestroyed(SevrvletContextEvent event){
    14         this.context = null;
    15     }
    16 }

    (2)注册监听器

    1 <listener>
    2     <listener-class>com.test.MyDataContextListener</listener-class>
    3 </listener>

    (3)测试
    一旦web应用启动的时候,我们就鞥在任意的servlet或者jsp中通过下面方式获取我们初始化的参数:

    String myData = (String) getServletContext().getAttribute("myData");

    2、spring中的contextLoaderListener

    ServletContext启动之后会调用ServletContextListener的contextInitialized方法,可以从这个方法开始:
    org.springframework.web.context.ContextLoaderListener类中的contextInitialized

    1 @Override
    2 public void contextInitialized(ServletContextEvent event) {
    3     // 初始化WebApplicationContext
    4     initWebApplicationContext(event.getServletContext());
    5 }

    这里有一个WebApplicationContext,WebApplicationContext继承自ApplicationContext,在ApplicationContext的基础上又追加了一些特定于web的操作与特性,看一下这个类的初始化源码:

     1 public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
     2     if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
     3         // web.xml 中存在多次ContextLoader定义
     4         throw new IllegalStateException(
     5                 "Cannot initialize context because there is already a root application context present - " +
     6                 "check whether you have multiple ContextLoader* definitions in your web.xml!");
     7     }
     8 
     9     Log logger = LogFactory.getLog(ContextLoader.class);
    10     servletContext.log("Initializing Spring root WebApplicationContext");
    11     if (logger.isInfoEnabled()) {
    12         logger.info("Root WebApplicationContext: initialization started");
    13     }
    14     long startTime = System.currentTimeMillis();
    15 
    16     try {
    17         // Store context in local instance variable, to guarantee that
    18         // it is available on ServletContext shutdown.
    19         if (this.context == null) {
    20             // 初始化WebApplicationContext
    21             this.context = createWebApplicationContext(servletContext);
    22         }
    23         if (this.context instanceof ConfigurableWebApplicationContext) {
    24             ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
    25             if (!cwac.isActive()) {
    26                 // The context has not yet been refreshed -> provide services such as
    27                 // setting the parent context, setting the application context id, etc
    28                 if (cwac.getParent() == null) {
    29                     // The context instance was injected without an explicit parent ->
    30                     // determine parent for root web application context, if any.
    31                     ApplicationContext parent = loadParentContext(servletContext);
    32                     cwac.setParent(parent);
    33                 }
    34                 configureAndRefreshWebApplicationContext(cwac, servletContext);
    35             }
    36         }
    37         // 记录在servletContext中
    38         servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
    39 
    40         ClassLoader ccl = Thread.currentThread().getContextClassLoader();
    41         if (ccl == ContextLoader.class.getClassLoader()) {
    42             currentContext = this.context;
    43         }
    44         else if (ccl != null) {
    45             currentContextPerThread.put(ccl, this.context);
    46         }
    47 
    48         if (logger.isDebugEnabled()) {
    49             logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
    50                     WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
    51         }
    52         if (logger.isInfoEnabled()) {
    53             long elapsedTime = System.currentTimeMillis() - startTime;
    54             logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
    55         }
    56 
    57         return this.context;
    58     }
    59     catch (RuntimeException ex) {
    60         logger.error("Context initialization failed", ex);
    61         servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
    62         throw ex;
    63     }
    64     catch (Error err) {
    65         logger.error("Context initialization failed", err);
    66         servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
    67         throw err;
    68     }
    69 }

    步骤如下:
    (1)WebApplicationContext存在性的验证
    (2)创建WebApplicationContext
    主要就是创建WebApplicationContext类,看一下创建过程的源码,在createWebApplicationContext方法中:
    org.springframework.web.context.ContextLoader类中的createWebApplicationContext

     1 protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
     2     Class<?> contextClass = determineContextClass(sc);
     3     // 这里判断使用什么样的类在web容器中作为IoC容器
     4     if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
     5         throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
     6                 "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
     7     }
     8     // 直接实例化需要产生的IoC容器,并设置IoC容器的各个参数,然后通过refresh启动容器的初始化
     9     return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
    10 }
    11 
    12 protected Class<?> determineContextClass(ServletContext servletContext) {
    13     String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
    14     if (contextClassName != null) {
    15         try {
    16             return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
    17         }
    18         catch (ClassNotFoundException ex) {
    19             throw new ApplicationContextException(
    20                     "Failed to load custom context class [" + contextClassName + "]", ex);
    21         }
    22     }
    23     else {
    24         contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
    25         try {
    26             return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
    27         }
    28         catch (ClassNotFoundException ex) {
    29             throw new ApplicationContextException(
    30                     "Failed to load default context class [" + contextClassName + "]", ex);
    31         }
    32     }
    33 }
    34 // 其中ContextLoader类中有这样的静态代码块:
    35 static {
    36     // Load default strategy implementations from properties file.
    37     // This is currently strictly internal and not meant to be customized
    38     // by application developers.
    39     try {
    40         ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
    41         defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
    42     }
    43     catch (IOException ex) {
    44         throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
    45     }
    46 }

    根据以上代码,肯定会存在当前目录下的属性文件ContextLoader.properties,你当然可以在源码中看到这个配置:
    spring-web下的resources文件夹下的org.springframework.web.context.ContextLoader.properties

    org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
    综合代码来看,在初始化过程中,程序首先会读取ContextLoader类的同目录下的属性文件ContextLoader.properties,并根据其中的配置提取将要实现的WebApplicationContext类的
    实现类,并且根据反射方式进行实例的创建
    (3)将实例记录在servletContext中
    (4)映射当前的类加载器与创建的实例到全局变量currentContextPerThread中

    二、DispatcherServlet

    1、DispatcherServlet的初始化
    在servlet初始化阶段,我们知道会首先调用其init方法,在DispatcherServlet中查找init方法的实现,查找方法直接查看该类的调用关系,在其父类中:
    org.springframework.web.servlet.HttpServletBean中的init方法:

     1 @Override
     2 public final void init() throws ServletException {
     3     if (logger.isDebugEnabled()) {
     4         logger.debug("Initializing servlet '" + getServletName() + "'");
     5     }
     6 
     7     // Set bean properties from init parameters.
     8     // 解析init-param 并封装到pvs中
     9     PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
    10     if (!pvs.isEmpty()) {
    11         try {
    12             // 将当前的这个servlet类转换成BeanWrapper,从而能够以spring的方式对init-param的值进行注入
    13             BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
    14             ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
    15             // 注册自定义的属性编辑器,一旦使用Resource类型的属性将会使用ResourceEditor进行解析
    16             bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
    17             // 空实现,留给子类覆盖
    18             initBeanWrapper(bw);
    19             // 属性注入
    20             bw.setPropertyValues(pvs, true);
    21         }
    22         catch (BeansException ex) {
    23             if (logger.isErrorEnabled()) {
    24                 logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
    25             }
    26             throw ex;
    27         }
    28     }
    29 
    30     // Let subclasses do whatever initialization they like.
    31     // 留给子类扩展
    32     initServletBean();
    33 
    34     if (logger.isDebugEnabled()) {
    35         logger.debug("Servlet '" + getServletName() + "' configured successfully");
    36     }
    37 }

    DispatcherServlet的初始化过程是通过将当前servlet类型实例转换为BeanWrapper类型实例,以便使用spring中提供的注入功能进行对应属性的注入,这些属性如contextAttribute、
    contextClass、nameSpace等,都可以在web.xml文件中以初始化参数的方式。DispatcherServlet继承自FrameworkServlet,FrameworkServlet类上包含同名属性,spring会保证这些
    这些参数被注入到对应的值中。属性注入主要包含以下几个步骤:

    (1)封装以及验证初始化参数
    ServletConfigPropertyValues除了封装属性还有对属性的验证功能
    org.springframework.web.servlet.HttpServletBean.ServletConfigPropertyValues类中

     1 public ServletConfigPropertyValues(ServletConfig config, Set<String> requiredProperties)
     2         throws ServletException {
     3 
     4     Set<String> missingProps = (!CollectionUtils.isEmpty(requiredProperties) ?
     5             new HashSet<>(requiredProperties) : null);
     6 
     7     Enumeration<String> paramNames = config.getInitParameterNames();
     8     while (paramNames.hasMoreElements()) {
     9         String property = paramNames.nextElement();
    10         Object value = config.getInitParameter(property);
    11         addPropertyValue(new PropertyValue(property, value));
    12         if (missingProps != null) {
    13             missingProps.remove(property);
    14         }
    15     }
    16 
    17     // Fail if we are still missing properties.
    18     if (!CollectionUtils.isEmpty(missingProps)) {
    19         throw new ServletException(
    20                 "Initialization from ServletConfig for servlet '" + config.getServletName() +
    21                 "' failed; the following required properties were missing: " +
    22                 StringUtils.collectionToDelimitedString(missingProps, ", "));
    23     }
    24 }
    25 
    26 // 从代码中得知,封装属性主要是对初始化的参数进行封装,也就是servlet中配置的<init-param>中配置的封装。

    (2)将当前的servlet实例转化成BeanWrapper实例
    PropertyAccessorFactory.forBeanPropertyAccess(this);是spring中提供的方法,主要作用就是将制定实例转化为spring中可以处理的BeanWrapper实例
    (3)注册相对于Resource的属性编辑器
    在当前实例的属性注入过程中一旦遇到Resource类型的属性就会使用ResourceEditor去解析
    (4)属性注入
    BeanWrapper为spring中的方法,支持spring的自动注入。其实我们最常用的属性注入无非是contextAttribute、contextClass、nameSpace等
    (5)servletBean实例化
    在ContextLoaderListener加载的时候已经创建了WebApplicationContext实例,而在这个函数中最重要的就是对这个类的进一步补充实例化
    看一下initServletBean源码:
    org.springframework.web.servlet.FrameworkServlet中

     1 @Override
     2 protected final void initServletBean() throws ServletException {
     3     getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
     4     if (logger.isInfoEnabled()) {
     5         logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
     6     }
     7     long startTime = System.currentTimeMillis();
     8 
     9     try {
    10         this.webApplicationContext = initWebApplicationContext();
    11         // 设计为子类覆盖
    12         initFrameworkServlet();
    13     }
    14     catch (ServletException | RuntimeException ex) {
    15         logger.error("Context initialization failed", ex);
    16         throw ex;
    17     }
    18 
    19     if (logger.isInfoEnabled()) {
    20         long elapsedTime = System.currentTimeMillis() - startTime;
    21         logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
    22                 elapsedTime + " ms");
    23     }
    24 }

    最为关键的初始化逻辑其实由initWebApplicationContext方法实现:

    2、WebApplicationContext的初始化

    initWebApplicationContext方法的主要工作就是创建或刷新WebApplicationContext实例并对servlet功能所使用的变量进行初始化
    org.springframework.web.servlet.FrameworkServlet类中

     1 protected WebApplicationContext initWebApplicationContext() {
     2     WebApplicationContext rootContext =
     3             WebApplicationContextUtils.getWebApplicationContext(getServletContext());
     4     WebApplicationContext wac = null;
     5 
     6     if (this.webApplicationContext != null) {
     7         // A context instance was injected at construction time -> use it
     8         // context实例在构造函数中被注入
     9         wac = this.webApplicationContext;
    10         if (wac instanceof ConfigurableWebApplicationContext) {
    11             ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
    12             if (!cwac.isActive()) {
    13                 // The context has not yet been refreshed -> provide services such as
    14                 // setting the parent context, setting the application context id, etc
    15                 if (cwac.getParent() == null) {
    16                     // The context instance was injected without an explicit parent -> set
    17                     // the root application context (if any; may be null) as the parent
    18                     cwac.setParent(rootContext);
    19                 }
    20                 // 刷新上下文环境
    21                 configureAndRefreshWebApplicationContext(cwac);
    22             }
    23         }
    24     }
    25     if (wac == null) {
    26         // No context instance was injected at construction time -> see if one
    27         // has been registered in the servlet context. If one exists, it is assumed
    28         // that the parent context (if any) has already been set and that the
    29         // user has performed any initialization such as setting the context id
    30         // 根据contextAttribute属性加载WebApplicationContext
    31         wac = findWebApplicationContext();
    32     }
    33     if (wac == null) {
    34         // No context instance is defined for this servlet -> create a local one
    35         wac = createWebApplicationContext(rootContext);
    36     }
    37 
    38     if (!this.refreshEventReceived) {
    39         // Either the context is not a ConfigurableApplicationContext with refresh
    40         // support or the context injected at construction time had already been
    41         // refreshed -> trigger initial onRefresh manually here.
    42         synchronized (this.onRefreshMonitor) {
    43             onRefresh(wac);
    44         }
    45     }
    46 
    47     if (this.publishContext) {
    48         // Publish the context as a servlet context attribute.
    49         String attrName = getServletContextAttributeName();
    50         getServletContext().setAttribute(attrName, wac);
    51         if (this.logger.isDebugEnabled()) {
    52             this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
    53                     "' as ServletContext attribute with name [" + attrName + "]");
    54         }
    55     }
    56 
    57     return wac;
    58 }

    对于本函数的初始化主要分为这几个部分:

    (1)寻找和创建对应的WebApplicationContext实例
    寻找和创建对应的WebApplicationContext实例主要分为以下几个步骤:
    1.1 通过构造函数的注入进行初始化
    1.2 通过contextAttribute进行初始化
    org.springframework.web.servlet.FrameworkServlet中的findWebApplicationContext方法

     1 @Nullable
     2 protected WebApplicationContext findWebApplicationContext() {
     3     String attrName = getContextAttribute();
     4     if (attrName == null) {
     5         return null;
     6     }
     7     WebApplicationContext wac =
     8             WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);
     9     if (wac == null) {
    10         throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");
    11     }
    12     return wac;
    13 }

    1.3 重新创建WebApplicationContext实例

    org.springframework.web.servlet.FrameworkServlet类中createWebApplicationContext

     1 protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
     2     // 获取servlet的初始化参数contextClass,如果没有默认匹配XmlWebApplicationContext.class
     3     Class<?> contextClass = getContextClass();
     4     if (this.logger.isDebugEnabled()) {
     5         this.logger.debug("Servlet with name '" + getServletName() +
     6                 "' will try to create custom WebApplicationContext context of class '" +
     7                 contextClass.getName() + "'" + ", using parent context [" + parent + "]");
     8     }
     9     if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
    10         throw new ApplicationContextException(
    11                 "Fatal initialization error in servlet with name '" + getServletName() +
    12                 "': custom WebApplicationContext class [" + contextClass.getName() +
    13                 "] is not of type ConfigurableWebApplicationContext");
    14     }
    15     // 通过反射方式实例化contextClass
    16     ConfigurableWebApplicationContext wac =
    17             (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
    18 
    19     wac.setEnvironment(getEnvironment());
    20     // parent为在ContextLoaderListener中创建的实例,在ContextLoaderListener加载的时候初始化的WebApplicationContext类型实例
    21     wac.setParent(parent);
    22     // 获取ContextConfigLocation属性,配置在servlet初始化参数中
    23     String configLocation = getContextConfigLocation();
    24     if (configLocation != null) {
    25         wac.setConfigLocation(configLocation);
    26     }
    27     // 初始化spring环境包括加载配置文件等
    28     configureAndRefreshWebApplicationContext(wac);
    29 
    30     return wac;
    31 }

    (2)configureAndRefreshWebApplicationContext刷新上下文环境

    org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext方法中

     1 protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
     2     if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
     3         // The application context id is still set to its original default value
     4         // -> assign a more useful id based on available information
     5         if (this.contextId != null) {
     6             wac.setId(this.contextId);
     7         }
     8         else {
     9             // Generate default id...
    10             wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
    11                     ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
    12         }
    13     }
    14 
    15     wac.setServletContext(getServletContext());
    16     wac.setServletConfig(getServletConfig());
    17     wac.setNamespace(getNamespace());
    18     wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
    19 
    20     // The wac environment's #initPropertySources will be called in any case when the context
    21     // is refreshed; do it eagerly here to ensure servlet property sources are in place for
    22     // use in any post-processing or initialization that occurs below prior to #refresh
    23     ConfigurableEnvironment env = wac.getEnvironment();
    24     if (env instanceof ConfigurableWebEnvironment) {
    25         ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
    26     }
    27 
    28     postProcessWebApplicationContext(wac);
    29     applyInitializers(wac);
    30     // 加载配置文件及整合parent到wac
    31     wac.refresh();
    32 }
    33 // 无论调用方式如何变化,只要使用ApplicationContext所提供的的功能最后都免不了使用公共父类AbstractApplicationContext提供的refresh()方法

    (3)刷新

    onRefresh是在FrameworkServlet类中提供的模板方法,在其子类DispatcherServlet中进行重写,主要用于刷新在web功能实现中所必须使用的全局变量。

     1 @Override
     2 protected void onRefresh(ApplicationContext context) {
     3     initStrategies(context);
     4 }
     5 
     6 protected void initStrategies(ApplicationContext context) {
     7     // 初始化MultipartResolver
     8     initMultipartResolver(context);
     9     // 初始化LocaleResolver
    10     initLocaleResolver(context);
    11     // 初始化ThemeResolver
    12     initThemeResolver(context);
    13     // 初始化HandlerMappings
    14     initHandlerMappings(context);
    15     // 初始化HandlerAdapters
    16     initHandlerAdapters(context);
    17     // 初始化HandlerExceptionResolvers
    18     initHandlerExceptionResolvers(context);
    19     // 初始化RequestToViewNameTranslator
    20     initRequestToViewNameTranslator(context);
    21     // 初始化ViewResolvers
    22     initViewResolvers(context);
    23     // 初始化FlashMapManager
    24     initFlashMapManager(context);
    25 }

    3.1 初始化MultipartResolver
    在spring中,MultipartResolver主要用来处理文件上传。常用的配置如下:

     1 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
     2     <property name="maxmunFileSize">
     3         <value>1000</value>
     4     </property>
     5 </bean>
     6 
     7 org.springframework.web.servlet.DispatcherServlet类中:
     8 private void initMultipartResolver(ApplicationContext context) {
     9     try {
    10         this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
    11         if (logger.isDebugEnabled()) {
    12             logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
    13         }
    14     }
    15     catch (NoSuchBeanDefinitionException ex) {
    16         // Default is no multipart resolver.
    17         this.multipartResolver = null;
    18         if (logger.isDebugEnabled()) {
    19             logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
    20                     "': no multipart request handling provided");
    21         }
    22     }
    23 }

    就写一个吧,其他的基本类似!

  • 相关阅读:
    Python----定义
    [转载]Morris Traversal方法遍历二叉树(非递归,不用栈,O(1)空间)
    彻底明白IP地址——计算相关地址
    [转载] 教你如何迅速秒杀掉:99%的海量数据处理面试题
    [转载]从B 树、B+ 树、B* 树谈到R 树
    [转载]Java抽象类和接口的学习
    [转载]字符串匹配的Boyer-Moore算法
    [转载]字符串匹配的KMP算法
    [转载]孤儿进程与僵尸进程[总结]
    [转载]Huffman编码压缩算法
  • 原文地址:https://www.cnblogs.com/ssh-html/p/11329828.html
Copyright © 2011-2022 走看看