Spring上下文在web容器中的启动过程

        Spring上下文在web容器中的启动过程,简单地说,就是包括IoC容器启动的基本过程Web容器的初始化并启动的过程

    IoC容器的启动过程就是建立上下文的过程,该上下文是与ServletContext相伴而生的,同时也是IoC容器在Web应用环境中的具体表现之一。由ContextLoaderListener启动的上下文为根上下文

        Spring应用在Web容器中启动的整个过程如下:

        
        

       按上图的步骤,各个部分细节如下:

          1. 在ContextLoaderListener中,实现的是ServletContextListener接口,这个接口里的函数会结合Web容器的生命周期被调用。因为ServletContextListener是ServletContext的监听者,如果ServletContext发生变化,会触发出相应的事件,而监听器一直在对这些事件进行监听,如果接收到了监听的事件,就会做出预先设计好的响应动作。由于ServletContext的变化而触发的监听器的响应具体包括:在服务器启动时,ServletContext被创建的时候;服务器关闭时,ServletContext将被销毁的时候等。对应这些事件及Web容器状态的变化,在监听器中定义了对应的事件响应的回调方法。比如在服务器启动时,ServletContextListener的contextInitialized()方法被调用,服务器将要关闭时,ServletContextLis-tener的contextDestroyed()方法被调用.

          2.在Web容器中,建立WebApplicationContext的过程,是在contextInitialized的接口实现中完成的。

contextInitialized就是调用initWebApplicationContext,所以也可以合为一步. 具体的载入IoC容器的过程是由ContextLoaderListener交由ContextLoader来完成的 .

public void contextInitialized(ServletContextEvent event) {
   initWebApplicationContext(event.getServletContext());
}

         在web.xml中,已经配置了ContextLoaderListener,这个ContextLoaderListener是Spring提供的类,是为在Web容器中建立IoC容器服务的,它实现了ServletContextListener接口。这个监听器主要功能是启动根IoC容器并把它载入到Web容器的主要功能模块,也是整个Spring Web应用加载IoC的第一个地方。从加载过程可以看到,首先从Servlet事件中得到ServletContext,然后可以读取配置在web.xml中的各个相关的属性值,接着ContextLoader会实例化WebApplicationContext,并完成其载入和初始化过程。这个被初始化的第一个上下文作为根上下文而存在,这个根上下文载入后,被绑定到Web应用程序的ServletContext上。任何需要访问根上下文的应用程序代码都可以从WebApplicationContextUtils类的静态方法中得到,具体取得根上下文的方法如下所示:

public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
		return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
     //ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE是默认的路径
	}

       

          3.在ContextLoader中,完成了两个IoC容器建立的基本过程,一个是在Web容器中建立起双亲IoC容器,另一个是生成相应的WebApplicationContext并将其初始化

         具体的初始化工作交给ContextLoader来完成,代码如下所示:

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
		if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
			throw new IllegalStateException(
					"Cannot initialize context because there is already a root application context present - " +
					"check whether you have multiple ContextLoader* definitions in your web.xml!");
		}

		Log logger = LogFactory.getLog(ContextLoader.class);
		servletContext.log("Initializing Spring root WebApplicationContext");
		if (logger.isInfoEnabled()) {
			logger.info("Root WebApplicationContext: initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
			// Store context in local instance variable, to guarantee that
			// it is available on ServletContext shutdown.
			if (this.context == null) {
				this.context = createWebApplicationContext(servletContext);
			}
			if (this.context instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
				if (!cwac.isActive()) {
					// The context has not yet been refreshed -> provide services such as
					// setting the parent context, setting the application context id, etc
					if (cwac.getParent() == null) {
						// The context instance was injected without an explicit parent ->
						// determine parent for root web application context, if any.
						ApplicationContext parent = loadParentContext(servletContext);
						cwac.setParent(parent);
					}
					configureAndRefreshWebApplicationContext(cwac, servletContext);
				}
			}
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

			ClassLoader ccl = Thread.currentThread().getContextClassLoader();
			if (ccl == ContextLoader.class.getClassLoader()) {
				currentContext = this.context;
			}
			else if (ccl != null) {
				currentContextPerThread.put(ccl, this.context);
			}

			if (logger.isDebugEnabled()) {
				logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
						WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
			}
			if (logger.isInfoEnabled()) {
				long elapsedTime = System.currentTimeMillis() - startTime;
				logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
			}

			return this.context;
		}
		catch (RuntimeException ex) {
			logger.error("Context initialization failed", ex);
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
			throw ex;
		}
		catch (Error err) {
			logger.error("Context initialization failed", err);
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
			throw err;
		}
	}

        在这个初始化过程中,完成根上下文在Web容器中的创建。这个根上下文是作为Web容器中唯一的实例而存在的,如果在这个初始化过程中,发现已经有根上下文被创建了,这里会抛出异常提示创建失败。

 

        4.完成这些基本的设置以后,通过对refresh方法的调用,重启整个IoC容器,就像一般的IoC容器的初始化过程一样.

 

        5.根上下文创建成功以后,会被存到Web容器的ServletContext中去,供需要时使用。

 

        特别提醒:

       应用可以在部署描述符中指定使用什么样的IoC容器,这个指定操作是通过CONTEXT_CLASS_PARAM参数的设置完成的。如果没有指定特定的IoC容器,将使用默认的IoC容器,也就是XmlWebApplicationContext对象作为在Web环境中使用的IoC容器。

转载于:https://my.oschina.net/mindfind/blog/1031585

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值