欢迎光临散文网 会员登陆 & 注册

(转载)漫谈Spring的启动与初始化(二)

2019-10-31 16:27 作者:觞翊の泽  | 我要投稿

 2017-08-06   |     |   540

地址:https://zouzls.github.io/2017/08/06/SpringInit/

上一篇关于Spring是如何启动的文章,主要是分析了从Tomcat启动到web.xml文件加载,再到通过ContextLoaderListener监听器开始初始化WebApplicationContext这个过程,如果不熟悉可以参考这篇-漫谈Spring的启动与初始化(一),但是上一篇还没有分析到Spring容器是如何通过web.xml里面配置的contextConfigLocation参数和Spring容器的配置文件applicationContext.xml来初始化Spring,本文着力于解决这个疑惑。

initWebApplicationContext方法

ContextLoaderListener监听到ServletContext初始化事件的时候就会调用ContextLoaderinitWebApplicationContext方法,这个方法完成了很多的工作,其中便有下面这段关键代码,源码如下:

createWebApplicationContext方法

下面进入该方法,源码如下:

其中determineContextClass(sc)方法是用来寻找实现WebApplicationContext接口的类,实现方法如下:

上面这两行代码就是决定返回的Class:如果开发人员在web.xml中配置了一个参数名为contextClass,值为WebApplicationContext接口实现类,那getInitParameter("contextClass")就会返回这个配置的实现类Class;如果没有配置,也就是contextClassName==null,那么通过defaultStrategies.getProperty(...)则会返回Spring默认的实现类XmlWebApplicationContext。可能有同学会好奇为什么是这个,这个类是从哪儿来的。
我们回头在ContextLoader这个类中最下面可以看到有这么几行静态代码段,在类一加载的时候执行,如下:

ContextLoader.class的同一个包下面,可以找到这个配置文件,其中只有一行配置如下:

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

XmlWebApplicationContext这个类就是WebApplicationContext这个接口最终的实现类,也是Spring启动时默认使用的类。其实还有一些实现类,让我们自己去加载applicationContext.xml,比如ClassPathXmlApplicationContext
这样在上述的createWebApplicationContext方法中,我们拿到的就是XmlWebApplicationContext.class,然后通过BeanUtils.instantiateClass(contextClass)方法根据类名创建对应实例,并且进行强制转换得到ConfigurableWebApplicationContext接口的实例,因为XmlWebApplicationContext是后者的实现类,所以这样转换是没问题的(当然没问题哈哈)。
那么createWebApplicationContext方法分析到此为止。


configureAndRefreshWebApplicationContext方法

在上面代码中我们通过XmlWebApplicationContext类创建了WebApplicationContext的实例,本节方法则是为该实例设置一些配置信息和创建各种bean。我们重点关注下面几行代码:

在Spring的项目中,经常要在web.xml中配置contextConfigLocation的参数,既然是在web.xml中配置的这些参数,为什么是在ServletContext中去取呢?在上一篇文章中分析过,Tomcat在加载web.xml文件时,会最终将该配置文件的配置属性参数以键值对的形式存放在每个web应用对应的ServletContext中,这样我们在web应用中的任何地方都可以拿到该参数值(后面还会提到ServletContext其他的使用场景)。

当然,如果我们没有在web.xml中配置该参数的话,XmlWebApplicationContext类也是有默认值的。

到这里,配置文件信息拿到了,再就是wac.refresh()方法了,这个方法具体实现在AbstractApplicationContext类中,进入该方法:

这个方法里面就是IOC容器初始化的大致步骤了。

after configureAndRefresh

初始化后的context被存放到了servletContext中,具体的就是存到了一个Map变量中,key值就是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE这个常量。这个key常量在WebApplicationContext接口中设置的。


另外,我们也可以使用Spring的WebApplicationContextUtils工具类获取这个WebApplicationContext(不过这里request获取ServletContext是有限制的,要求servlet-api.jar 包的版本是在3.0以上)方式如下:

WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());

到这里Spring的启动与初始化应该就结束了,这里面要理清ServletContext和Spring容器的关系,整个Spring容器被放置在ServletContext这样一个类似于Map的结构中。ServletContext 从字面上理解也是Servlet的容器,被 Servlet 程序间接用来与外层 Web 容器通信,例如写日志,转发请求等。每一个 Web 应用程序含有一个Context ,被Web 应用内的各个程序共享。因为Context 可以用来保存资源并且共享,所以ServletContext 的常用场景是Web级应用缓存—- 把不经常更改的内容读入内存,所以服务器响应请求的时候就不需要进行慢速的磁盘I/O 了。

-EOF-


(转载)漫谈Spring的启动与初始化(二)的评论 (共 条)

分享到微博请遵守国家法律