IoC容器在web容器中的初始化过程

以前学习spring原理的时候,都是直接new一个IOC容器,如下:

AnnotationConfigApplicationContext aac =
				new AnnotationConfigApplicationContext("com.mydemo");

那么,spring在实际的web项目中,是如何初始化的呢?
首先来看看我们在使用 Spring + Spring MVC 框架开发的时候是如何配置的。
Web容器中使用Spring MVC,要配置web.xml:一般会配置context-param >> listener >> fileter >> servlet,并且执行顺序从左到右。

context-param :容器会将<context-param>转换为键值对,并交给servletContext管理。
listener :监听器
fileter :过滤器

配置spring:可以看到初始化spring需要依赖于一个监听器ContextLoaderListener

<!-- 启动Spring的容器 -->
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener> 
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener>

现在就来看看是怎么初始化springIOC容器的

ContextLoaderListener

首先可以看到ContextLoaderListener extends ContextLoader implements ServletContextListener ,实现了ServletContextListener表示了它是一个监听器,并且它在web.xml中注册了。

1.首先执行的便是contextInitialized方法:在web容器启动时,会触发容器初始化事件,此时ContextLoaderListener会监听到这个事件

@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
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!");
}
。。。。。。。。。
long startTime = System.currentTimeMillis();
try {
	if (this.context == null) {
		//创建一个springIOC容器
		this.context = createWebApplicationContext(servletContext);
	}
	if (this.context instanceof ConfigurableWebApplicationContext) {
		ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
		if (!cwac.isActive()) {
			if (cwac.getParent() == null) {
				ApplicationContext parent = loadParentContext(servletContext);
				cwac.setParent(parent);
			}
			//配置刷新ioc容器
			configureAndRefreshWebApplicationContext(cwac, servletContext);
		}
	}
	//把初始化完毕的ioc容器放到servletContext中
	servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

。。。。。。。。。。。。
}

2.看一下是如何创建一个ioc容器的

protected WebApplicationContext createWebApplicationContext(ServletContext sc) {	
//确定使用哪个WebApplicationContext的实现类作为spring的ioc容器
	Class<?> contextClass = determineContextClass(sc);
	if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
。。。。
	}
	//创建ioc容器实例
	return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}

2.1确定使用哪个WebApplicationContext的实现类作为springioc容器

protected Class<?> determineContextClass(ServletContext servletContext) {
//如果在web.xml中配置了一个参数名为contextClass,值为WebApplicationContext接口实现类,
//那getInitParameter("contextClass")就会返回这个配置的实现类Class
	String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
	if (contextClassName != null) {
		try {
			return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
		}
	。。。。。。。。
	}
	else {
	//返回Spring默认的实现类XmlWebApplicationContext
		contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
		try {
			return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
		}
。。。。。。。。。。。。。。
	}
}
//看看这个默认策略defaultStrategies是个啥玩意儿
static {
	。。。。。。。。
	try {
		ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
		defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
。。。。。。。。。。
}
private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";
ContextLoader.properties内容:
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
//发现这个默认策略是放在一个静态代码块中的,意味着ContextLoaderListener一加载的时候,就
//从配置文件ContextLoader.properties中加载了一个配置WebApplicationContext=XmlWebApplicationContext
//所以从这我们就可以知道XmlWebApplicationContext这个类就是WebApplicationContext这个接口最终的实现类,
//也是Spring启动时默认使用的类

3.为IOC实例设置一些配置信息和创建各种bean
进入configureAndRefreshWebApplicationContext方法

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
   ...
   wac.setServletContext(sc);
   //关键代码一:在ServletContext中获取contextConfigLocation值,就是在web.xml配置的spring配置文件的地址
   //补充说明:Tomcat在加载web.xml文件时,会最终将该配置文件的配置属性参数以键值对的形式存放在每个web应用
   //对应的ServletContext中,这样我们在web应用中的任何地方都可以拿到该参数值
   configLocationParam = sc.getInitParameter("contextConfigLocation");
   if(configLocationParam != null) {
       wac.setConfigLocation(configLocationParam);
   }
   ...
   //关键代码二:刷新XmlWebApplicationContext
   wac.refresh();
}

refresh方法里面就是IOC容器初始化的大致步骤了。看过spring源码的话,后面的都懂的了。

4.把初始化完毕的ioc容器放到servletContext

 //关键代码:
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

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

String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值