个人感觉《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. }

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

spring源码学习之springMVC(一)的更多相关文章

  1. 【spring源码学习】springMVC之映射,拦截器解析,请求数据注入解析,DispatcherServlet执行过程

    [一]springMVC之url和bean映射原理和源码解析 映射基本过程 (1)springMVC配置映射,需要在xml配置文件中配置<mvc:annotation-driven >  ...

  2. spring源码学习之springMVC(二)

    接着上一篇.继续来看springMVC中最和我们开发中接近的一部分内容: DispatcherServlet的逻辑处理 作者写到在DispatcherServlet类中存在doGet.doPost之类 ...

  3. spring源码学习之路---深入AOP(终)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章和各位一起看了一下sp ...

  4. spring源码学习之路---IOC初探(二)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章当中我没有提及具体的搭 ...

  5. Spring源码学习

    Spring源码学习--ClassPathXmlApplicationContext(一) spring源码学习--FileSystemXmlApplicationContext(二) spring源 ...

  6. Spring源码学习-容器BeanFactory(四) BeanDefinition的创建-自定义标签的解析.md

    写在前面 上文Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签对Spring默认标签的解析做了详解,在xml元素的解析中,Spri ...

  7. Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签

    写在前面 上文Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作中Spring对XML解析后创建了对应的Docum ...

  8. Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作

    写在前面 上文 Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件主要讲Spring容器创建时通过XmlBeanDefinitionReader读 ...

  9. Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件

    写在前面 从大四实习至今已一年有余,作为一个程序员,一直没有用心去记录自己工作中遇到的问题,甚是惭愧,打算从今日起开始养成写博客的习惯.作为一名java开发人员,Spring是永远绕不过的话题,它的设 ...

随机推荐

  1. c# Data = select new{} 返回值的显示

  2. springboot2.0 使用aop实现PageHelper分页

    参考: https://blog.csdn.net/qq_24076135/article/details/85212081 https://www.jianshu.com/p/036d31ae77d ...

  3. Luogu P2484 [SDOI2011]打地鼠(模拟+前缀和)

    P2484 [SDOI2011]打地鼠 题意 题目描述 打地鼠是这样的一个游戏:地面上有一些地鼠洞,地鼠们会不时从洞里探出头来很短时间后又缩回洞中.玩家的目标是在地鼠伸出头时,用锤子砸其头部,砸到的地 ...

  4. activeMQ消息队列安装配置

    1.  下载 到官网下载最新版本,有windows版本和linux版本的. http://activemq.apache.org/download.html 2.   windows下部署 Activ ...

  5. odoo 下 get_object_reference 函数

    get_object_reference是 ir.model.data 模块中下的一个函数 该函数通过调用ir.model.data 模块中另外一个函数 xmlid_lookup 返回结果 def g ...

  6. Java 的 JJWT 实现 JWT

    JJWT是一个提供端到端的JWT创建和验证的Java库 依赖 <dependency> <groupId>io.jsonwebtoken</groupId> < ...

  7. 关于将ECharts引入到项目中的几种方式

    方式一.在webpack中使用ECharts 1.npm安装ECharts npm install echarts --save 2.引入ECharts 通过 npm 上安装的 ECharts 和 z ...

  8. LUOGU P1337 [JSOI2004]平衡点 / 吊打XXX(模拟退火)

    传送门 解题思路 学习了一下玄学算法--模拟退火,首先要求平衡处,也就是求势能最小的地方,就是求这个点到所有点的距离*重量最小.剩下的几乎是模拟退火的板子了. #include<iostream ...

  9. SpringBoot_01_SpringBoot入门

    1 Spring的优点分析 Spring是Java企业版(Java Enterprise Edition,JEE,也称J2EE)的轻量级代替品.无需开发重量级的Enterprise JavaBean( ...

  10. Java(8)中List的遍历方式总结

    本篇文章主要讲述了List这一集合类型在Java,包括Java8中的遍历方式,不包括其他的过滤,筛选等操作,这些操作将会在以后的文章中得到提现,由List可以类推到Set等类似集合的遍历方式. pub ...