在项目的web.xml中配置

  1. <listener>
  2. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  3. </listener>

此配置为spring容器加载入口,因为其javax.servlet.ServletContextListener接口。

下面代码为ServletContextListener的源码:

  1. public interface ServletContextListener extends EventListener {
  2. /**
  3. ** Notification that the web application initialization
  4. ** process is starting.
  5. ** All ServletContextListeners are notified of context
  6. ** initialization before any filter or servlet in the web
  7. ** application is initialized.
  8. */
  9.  
  10. public void contextInitialized ( ServletContextEvent sce );
  11.  
  12. /**
  13. ** Notification that the servlet context is about to be shut down.
  14. ** All servlets and filters have been destroy()ed before any
  15. ** ServletContextListeners are notified of context
  16. ** destruction.
  17. */
  18. public void contextDestroyed ( ServletContextEvent sce );
  19. }

其中contextInitialized方法为web应用加载入口,实现此方法即可在其中加载自定义初始化web应用。

回过头看ContextLoaderListener中的初始化工作:

  1. /**
  2. * Initialize the root web application context.
  3. */
  4. public void contextInitialized(ServletContextEvent event) {
  5. this.contextLoader = createContextLoader();
  6. if (this.contextLoader == null) {
  7. this.contextLoader = this;
  8. }
  9. this.contextLoader.initWebApplicationContext(event.getServletContext());
  10. }

其具体初始化工作在其父类org.springframework.web.context.ContextLoader中的initWebApplicationContext方法中进行:

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

下面我们来分析一下上面的方法中的具体工作:

1)方法determineContextClass其返回一个WebApplicationContext的实现类,要么是默认的XmlWebApplicationContext,要么是一个指定的自定义的类。

先看方法源码:

  1. /**
  2. * Return the WebApplicationContext implementation class to use, either the
  3. * default XmlWebApplicationContext or a custom context class if specified.
  4. * @param servletContext current servlet context
  5. * @return the WebApplicationContext implementation class to use
  6. * @see #CONTEXT_CLASS_PARAM
  7. * @see org.springframework.web.context.support.XmlWebApplicationContext
  8. */
  9. protected Class<?> determineContextClass(ServletContext servletContext) {
  10. String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
  11. if (contextClassName != null) {
  12. try {
  13. return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
  14. }
  15. catch (ClassNotFoundException ex) {
  16. throw new ApplicationContextException(
  17. "Failed to load custom context class [" + contextClassName + "]", ex);
  18. }
  19. }
  20. else {
  21. contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
  22. try {
  23. return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
  24. }
  25. catch (ClassNotFoundException ex) {
  26. throw new ApplicationContextException(
  27. "Failed to load default context class [" + contextClassName + "]", ex);
  28. }
  29. }
  30. }

先查看是否有用户自定义的context类,其配置方式是在web.xml中配置初始化属性其name为contextClass,原因是:

  1. /**
  2. * Config param for the root WebApplicationContext implementation class to use: {@value}
  3. * @see #determineContextClass(ServletContext)
  4. * @see #createWebApplicationContext(ServletContext, ApplicationContext)
  5. */
  6. public static final String CONTEXT_CLASS_PARAM = "contextClass";

在web.xml中的配置例如:

  1. <context-param>
  2. <param-name>contextClass</param-name>
  3. <param-value>xxxxxxxxxx</param-value>
  4. </context-param>

如果没有自定义配置的话,实现加载其默认WebApplicationContext实现类org.springframework.web.context.support.XmlWebApplicationContext。

2)方法createWebApplicationContext将determineContextClass方法返回的Class类实例化。并将其实例类向上转型为ConfigurableWebApplicationContext类型。

默认的返回应该是ConfigurableWebApplicationContext的子类org.springframework.web.context.support.XmlWebApplicationContext实例。

下面是方法的源码:

  1. /**
  2. * Instantiate the root WebApplicationContext for this loader, either the
  3. * default context class or a custom context class if specified.
  4. * <p>This implementation expects custom contexts to implement the
  5. * {@link ConfigurableWebApplicationContext} interface.
  6. * Can be overridden in subclasses.
  7. * <p>In addition, {@link #customizeContext} gets called prior to refreshing the
  8. * context, allowing subclasses to perform custom modifications to the context.
  9. * @param sc current servlet context
  10. * @return the root WebApplicationContext
  11. * @see ConfigurableWebApplicationContext
  12. */
  13. protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
  14. Class<?> contextClass = determineContextClass(sc);
  15. if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
  16. throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
  17. "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
  18. }
  19. return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
  20. }

3)方法configureAndRefreshWebApplicationContext配置web应用

源码为:

  1. protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
  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. String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
  6. if (idParam != null) {
  7. wac.setId(idParam);
  8. }
  9. else {
  10. // Generate default id...
  11. if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) {
  12. // Servlet <= 2.4: resort to name specified in web.xml, if any.
  13. wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
  14. ObjectUtils.getDisplayString(sc.getServletContextName()));
  15. }
  16. else {
  17. wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
  18. ObjectUtils.getDisplayString(sc.getContextPath()));
  19. }
  20. }
  21. }
  22.  
  23. wac.setServletContext(sc);
  24. String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM);
  25. if (initParameter != null) {
  26. wac.setConfigLocation(initParameter);
  27. }
  28. customizeContext(sc, wac);
  29. wac.refresh();
  30. }

其中String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM);获取在web.xml中配置的contextConfigLocation参数来确定spring配置文件的位置。

其中的ConfigurableWebApplicationContext类型参数实际上是其子类org.springframework.web.context.support.XmlWebApplicationContext的类型参数,

其中方法customizeContext是定制化conext的方法,如果没有在web.xml中配置contextInitializerClasses初始化参数则此方法不做任何工作。

其中wac.refresh();方法其是在org.springframework.web.context.support.XmlWebApplicationContext的父类org.springframework.context.support.AbstractApplicationContext中实现。它才开始真正的spring配置工作。

spring容器启动原理分析1的更多相关文章

  1. Spring Boot 启动原理分析

    https://yq.aliyun.com/articles/6056 转 在spring boot里,很吸引人的一个特性是可以直接把应用打包成为一个jar/war,然后这个jar/war是可以直接启 ...

  2. spring boot启动原理步骤分析

    spring boot最重要的三个文件:1.启动类 2.pom.xml 3.application.yml配置文件 一.启动类->main方法 spring boot启动原理步骤分析 1.spr ...

  3. 从头看看Tomcat启动Spring容器的原理

    通过带注解Spring Boot可以启动一个web容器,并初始化bean容器.那么Tomcat启动并初始化spring容器的原理是怎样的? Tomcat启动web程序时会创建一对父子容器(图1): 有 ...

  4. Spring5深度源码分析(三)之AnnotationConfigApplicationContext启动原理分析

    代码地址:https://github.com/showkawa/spring-annotation/tree/master/src/main/java/com/brian AnnotationCon ...

  5. Spring Boot -- 启动流程分析之ApplicationContext 中

    上一节我们已经分析到AbsractApplicationContext类refresh方法中的postProcessBeanFactory方法,在分析registerBeanPostProcessor ...

  6. SpringBoot启动原理分析

    用了差不多两年的SpringBoot了,可以说对SpringBoot已经很熟了,但是仔细一想SpringBoot的启动流程,还是让自己有点懵逼,不得不说是自己工作和学习的失误,所以以此文对Spring ...

  7. Spring依赖注入原理分析

    在分析原理之前我们先回顾下依赖注入的概念: 我们常提起的依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念.具体含义是:当某个角色( ...

  8. Spring Boot启动原理解析

    Spring Boot启动原理解析http://www.cnblogs.com/moonandstar08/p/6550758.html 前言 前面几章我们见识了SpringBoot为我们做的自动配置 ...

  9. spring容器IOC原理解析

    原理简单介绍: Spring容器的原理,其实就是通过解析xml文件,或取到用户配置的bean,然后通过反射将这些bean挨个放到集合中,然后对外提供一个getBean()方法,以便我们获得这些bean ...

随机推荐

  1. Beta阶段项目复审

    复审人:王李焕 六指神功:http://www.cnblogs.com/teamworkers/ wt.dll:http://www.cnblogs.com/TeamOf/ 六个核桃:http://w ...

  2. 201521123107 《Java程序设计》第4周学习总结

    第4周作业-面向对象设计与继承 1.本周学习总结 2.书面作业 1.注释的应用 使用类的注释与方法的注释为前面编写的类与方法进行注释,并在Eclipse中查看.(截图) 对类的注释: 所得到的效果: ...

  3. 201521123105 第四周Java学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 继承与多态的概念与实现父类与之类的关系解决代码复用的办法 2. 书面作业 2.1 将在网上商 ...

  4. 201521123007《Java程序设计》第11周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 本次PTA作业题集多线程 1. 互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) ...

  5. 201521123103 《java学习笔记》 第十四周学习总结

    一.本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 二.书面作业 1. MySQL数据库基本操作 1.1建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现 ...

  6. 201521123106 《Java程序设计》第14周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自 ...

  7. 杭电acm-2007平方和立方和

    #include<stdio.h>int main(){         int t,m,n,x,y,i;     while(scanf("%d%d",&n, ...

  8. 深入理解计算机系统(2.5)------C语言中的有符号数和无符号数以及扩展和截断数字

    上一篇博客我们讲解了计算机中整数的表示,包括无符号编码和补码编码,以及它们之间的互相转换,个人觉得那是非常重要的知识要点.这篇博客我们将介绍C语言中的有符号数和无符号数以及扩展和截断数字. 1.C语言 ...

  9. 框架应用:Mybatis (一) - 入门案例

    ORM框架 在实际开发中,工程中本质的任务是从数据库中获取数据,然后对数据进行操作,又或者写入数据.开发时语言是大多是面向对象的工程语言,这个时候就必须进行工程语言和数据库连接语言的转换,也就是所谓的 ...

  10. Eclipse dynamic web project 插件

    下载了Eclipse Oxygen   发现没有Dynamic web  Project 首先我们先了解下Dynamic  Web Project  If you want to create a c ...