Spring源码分析3----SpringMVC

 2019-10-17 22:04  阅读(911)
文章分类:Spring boot

Spring源码分析3—-SpringMVC

目录(?)[+]

一、Web环境中的Spring MVC

用大体上看,在使用Spring MVC的时候,需要在web.xml中配置DispatcherServlet,这个DispatcherServlet可以看成是一个前端控制器的具体实现,还需要在Bean定义中配置Web请求和COntroller(控制器)的对应关系,以及各种视图的展现方式。

Spring IoC是一个独立的模块,它并不是直接在Web容器中发挥作用的,如果要在Web环境中使用IoC容器,需要Spring为IoC设计一个启动过程,把IoC容器导入,并在Web容器中建立起来。具体来说,这个启动过程是和Web容器的启动过程集成在一起的。在这个过程中,一方面处理Web容器的启动,另一方面通过设计特定的Web容器拦截器,将IoC容器载入到Web环境中来,并将其初始化。在这个过程建立完成以后,IoC容器才能正常工作,而Spring MVC是建立是IoC容器的基础上的,这样才能建立起MVC框架的运行机制,从而响应从Web容器传递的HTTP请求。

下面以Tomcat作为Web容器的例子进行分析。

[html]
view plain
copy

20191017100406\_1.png
20191017100406\_2.png

  1. ……
  2. <**servlet**>
  3. <**servlet-name**>springmvc</**servlet-name**>
  4. <**servlet-class**>org.springframework.web.servlet.DispatcherServlet</**servlet-class**>
  5. <**init-param**>
  6. <**param-name**>contextConfigLocation</**param-name**>
  7. <**param-value**>classpath:/applicationContext.xml</**param-value**>
  8. </**init-param**>
  9. <**load-on-startup**>1</**load-on-startup**>
  10. <**async-supported**>true</**async-supported**>
  11. </**servlet**>
  12. <**servlet-mapping**>
  13. <**servlet-name**>springmvc</**servlet-name**>
  14. <**url-pattern**>/</**url-pattern**>
  15. </**servlet-mapping**>
  16. <**listener**>
  17. <**listener-class**>
  18. org.springframework.web.context.ContextLoaderListener
  19. </**listener-class**>
  20. <**listener**>
  21. ……

作为Spring MVC的启动类,ContextLoaderListener被定义为一个监听器,这个监听器是与Web服务器的生命周期相关联的,由ContextLoaderListener监听器负责完成IoC容器在Web环境中的启动工作。

二、上下文在Web容器中的启动

2.1.IoC容器启动的基本过程

IoC容器的启动过程就是建立上下文的过程,该上下文是与ServletContext相伴而生的,同时也是IoC容器在Web应用环境中的具体表现之一。由ContextLoaderListener启动的上下文为根上下文。在根上下文的基础上,还有一个与Web MVC相碰的上下文 用来保持控制器(DispatchServlet)需要的MVC对象,作为根上下文的子上下文,构成一个层次化的上下文体系。在Web容器中启动Spring应用程序时,首先建立根上下文,然后建立这个上下文体系的,这个上下文体系的建立是由COntextLoader来完成的,具体过程由下:

[java]
view plain
copy

20191017100406\_3.png
20191017100406\_4.png

  1. **public****class ContextLoaderListener extends ContextLoader implements** ServletContextListener {
  2. public ContextLoaderListener() {
  3. }
  4. public ContextLoaderListener(WebApplicationContext context) {
  5. super(context);
  6. }
  7. @Override
  8. **public****void** contextInitialized(ServletContextEvent event) {
  9. initWebApplicationContext(event.getServletContext()); // ——->
  10. }
  11. @Override
  12. **public****void** contextDestroyed(ServletContextEvent event) {
  13. closeWebApplicationContext(event.getServletContext());
  14. ContextCleanupListener.cleanupAttributes(event.getServletContext());
  15. }
  16. }

[java]
view plain
copy

20191017100406\_5.png
20191017100406\_6.png

  1. //——————————-
  2. // ContextLoader
  3. public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
  4. if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
  5. **throw****new** IllegalStateException(
  6. “Cannot initialize context because there is already a root application context present – “ +
  7. “check whether you have multiple ContextLoader* definitions in your web.xml!”);
  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. try {
  16. // Store context in local instance variable, to guarantee that
  17. // it is available on ServletContext shutdown.
  18. if (this.context == null) {
  19. // ———————–>
  20. this.context = createWebApplicationContext(servletContext);
  21. }
  22. if (this.context instanceof ConfigurableWebApplicationContext) {
  23. ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
  24. if (!cwac.isActive()) {
  25. // The context has not yet been refreshed -> provide services such as
  26. // setting the parent context, setting the application context id, etc
  27. if (cwac.getParent() == null) {
  28. // The context instance was injected without an explicit parent ->
  29. // determine parent for root web application context, if any.
  30. // ——————–>
  31. ApplicationContext parent = loadParentContext(servletContext);
  32. cwac.setParent(parent);
  33. }
  34. // ——————->
  35. configureAndRefreshWebApplicationContext(cwac, servletContext);
  36. }
  37. }
  38. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
  39. ClassLoader ccl = Thread.currentThread().getContextClassLoader();
  40. if (ccl == ContextLoader.class.getClassLoader()) {
  41. currentContext = this.context;
  42. }
  43. **else****if (ccl != null**) {
  44. currentContextPerThread.put(ccl, this.context);
  45. }
  46. if (logger.isDebugEnabled()) {
  47. logger.debug(“Published root WebApplicationContext as ServletContext attribute with name [“ +
  48. WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + “]”);
  49. }
  50. if (logger.isInfoEnabled()) {
  51. long elapsedTime = System.currentTimeMillis() – startTime;
  52. logger.info(“Root WebApplicationContext: initialization completed in “ + elapsedTime + ” ms”);
  53. }
  54. **return****this**.context;
  55. }
  56. catch (RuntimeException ex) {
  57. logger.error(“Context initialization failed”, ex);
  58. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
  59. throw ex;
  60. }
  61. catch (Error err) {
  62. logger.error(“Context initialization failed”, err);
  63. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
  64. throw err;
  65. }
  66. }
  67. **protected****void** configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
  68. if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
  69. String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
  70. if (idParam != null) {
  71. wac.setId(idParam);
  72. }
  73. else {
  74. wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
  75. ObjectUtils.getDisplayString(sc.getContextPath()));
  76. }
  77. }
  78. wac.setServletContext(sc);
  79. String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
  80. if (configLocationParam != null) {
  81. wac.setConfigLocation(configLocationParam);
  82. }
  83. ConfigurableEnvironment env = wac.getEnvironment();
  84. if (env instanceof ConfigurableWebEnvironment) {
  85. ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
  86. }
  87. customizeContext(sc, wac);
  88. wac.refresh(); // ——————>
  89. }

[java]
view plain
copy

20191017100406\_7.png
20191017100406\_8.png

  1. // ——————————————————-
  2. **public****interface ConfigurableApplicationContext extends** ApplicationContext, Lifecycle, Closeable {
  3. String CONFIG_LOCATION_DELIMITERS = “,; \t\n”;
  4. String CONVERSION_SERVICE_BEAN_NAME = “conversionService”;
  5. String LOAD_TIME_WEAVER_BEAN_NAME = “loadTimeWeaver”;
  6. String ENVIRONMENT_BEAN_NAME = “environment”;
  7. String SYSTEM_PROPERTIES_BEAN_NAME = “systemProperties”;
  8. String SYSTEM_ENVIRONMENT_BEAN_NAME = “systemEnvironment”;
  9. void setId(String id);
  10. void setParent(ApplicationContext parent);
  11. @Override
  12. ConfigurableEnvironment getEnvironment();
  13. void setEnvironment(ConfigurableEnvironment environment);
  14. void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
  15. void addApplicationListener(ApplicationListener<?> listener);
  16. void addProtocolResolver(ProtocolResolver resolver);
  17. // ———————>
  18. void refresh() throws BeansException, IllegalStateException;
  19. void registerShutdownHook();
  20. @Override
  21. void close();
  22. boolean isActive();
  23. ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
  24. }

[java]
view plain
copy

20191017100406\_9.png
20191017100406\_10.png

  1. //————————————————————
  2. // public abstract class AbstractApplicationContext extends DefaultResourceLoader
  3. // implements ConfigurableApplicationContext, DisposableBean
  4. @Override
  5. **public****void refresh() throws** BeansException, IllegalStateException {
  6. synchronized (this.startupShutdownMonitor) {
  7. prepareRefresh();
  8. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  9. prepareBeanFactory(beanFactory);
  10. try {
  11. postProcessBeanFactory(beanFactory);
  12. invokeBeanFactoryPostProcessors(beanFactory);
  13. registerBeanPostProcessors(beanFactory);
  14. initMessageSource();
  15. initApplicationEventMulticaster();
  16. onRefresh();
  17. registerListeners();
  18. finishBeanFactoryInitialization(beanFactory);
  19. finishRefresh();
  20. }
  21. catch (BeansException ex) {
  22. if (logger.isWarnEnabled()) {
  23. logger.warn(“Exception encountered during context initialization – “ +
  24. “cancelling refresh attempt: “ + ex);
  25. }
  26. destroyBeans();
  27. cancelRefresh(ex);
  28. throw ex;
  29. }
  30. finally {
  31. resetCommonCaches();
  32. }
  33. }
  34. }

20191017100406\_11.png 在Web.xml,已经配置了ContextLoaderListener,这个ContextLoaderListener是Spring提供的类,是为在Web容器中建立IoC容器服务的,它实现了ServletContextListener接口,这个接口提供了与Servlet生命周期的回调。而在Web容器中,建立WebApplicationContext的过程,是在contextInitialized的接口实现中完成的。具体的载入IoC容器的过程是由ContextLoaderListener交由ContextLoaderg来完成的,而ContextLoader本身就是ContextLoaderListener的基类。

在ContextLoader中,完成了两个IoC容器建立的基本过程,一个是在Web容器中建立起双亲IoC容器,另一个是生成相应的WebApplicationContext并将其初始化。 转载出处:http://blog.csdn.net/oChangWen/article/details/61414380


来源:[]()

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> Spring源码分析3----SpringMVC

相关推荐