spring源码基础(二)

本文深入解析了Spring框架中ContextLoaderListener的初始化过程,重点介绍了其父类ContextLoader的加载机制,包括静态常量、静态代码块的作用,以及initWebApplicationContext方法如何创建和配置WebApplicationContext对象,最终加载applicationContext.xml。
摘要由CSDN通过智能技术生成

本篇,介绍ContextLoaderListener的父类ContextLoader类的详细加载,进一步了解ContextLoaderListener初始化的时候会做哪些工作。

该类中的部分静态常量和静态代码块如下:

public static final String CONTEXT_CLASS_PARAM = "contextClass";

private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";

private static final Properties defaultStrategies;

static {
	try {
		ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
		defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
	}
	catch (IOException ex) {
		throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
	}
}

ContextLoader.properties配置文件内容:

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

加载好properties文件,通过参数显而易见这个配置文件和后边加载WebApplication有关,暂且等待备用。

接下来,知道首先加载的方法是initWebApplicationContext方法,代码如下(日志和注释去除):

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) {
				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);
					}
					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);
			}

			return this.context;
		}
		catch (RuntimeException ex) {
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
			throw ex;
		}
		catch (Error err) {
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
			throw err;
		}
	}

该方法最终返回的是WebApplicationContext 对象,由于初次加载,执行createWebApplicationContext(servletContext);

createWebApplicationContext 方法调用 determineContextClass 方法;该方法最终返回的是XmlWebApplicationContext

determineContextClass方法代码中,String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);获取

ContextLoader类有静态常量:public static final String CONTEXT_CLASS_PARAM = "contextClass";

初始化时尚未存在该值,因此执行创建,执行以下:

contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
try {
	return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
}

显然,从defaultStrategies中加载完整类名,并通过ContextLoader.class.getClassLoader()加载并返回XmlWebApplicationContext;

回到initWebApplicationContext 方法,接下来执行 configureAndRefreshWebApplicationContext 方法;

configureAndRefreshWebApplicationContext 方法中调用了AbstractApplicationContext(实现了ConfigurableApplicationContext

接口refresh方法,

refresh方法调用了obtainFreshBeanFactory

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	refreshBeanFactory();
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	return beanFactory;
}

obtainFreshBeanFactory 调用了AbstractRefreshableApplicationContext类的refreshBeanFactory方法,

@Override
	protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

refreshBeanFactory调用了XmlWebApplicationContextloadBeanDefinitions

@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		beanDefinitionReader.setEnvironment(getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		initBeanDefinitionReader(beanDefinitionReader);
		loadBeanDefinitions(beanDefinitionReader);
	}

loadBeanDefinitions中加载了对应的applicationContext.xml

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			for (String configLocation : configLocations) {
				reader.loadBeanDefinitions(configLocation);
			}
		}
	}

自此,ContextLoaderListener类加载applicationContext.xml的过程完成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值