2、Spring源码学习:认识加载 xml 文件的 ClassPathXmlApplicationContext

本文围绕ClassPathXmlApplicationContext展开,绘制了从其开始的UML图,关注ApplicationContext。介绍了其特性,如配置文件路径格式、bean覆盖规则等。还比对了与FileSystemXmlApplicationContext,分析了构造方法内部逻辑,提及ConfigurableApplicationContext.refresh()接口定义,最后介绍了eager class特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

体能状态先于精神状态,习惯先于决心,聚焦先于喜好

这是一篇很水的文章

因为目前了解还不多,只是按图索骥,画了一下通过XML 初始化 Spring 容器的大体的 UML 类关系图

入口

下面这行代码你一定很熟悉,这是加载 Spring xml 文件的常规操作
ApplicationContext 是接口,ClassPathXmlApplicationContext 是集大成者,也是ApplicationContext 的实现类

ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
private static ApplicationContext ctx;

static {
	ctx=new ClassPathXmlApplicationContext(new String[]{
			"classpath*:springContext/spring-db-beans.xml"});
}
	
从 ClassPathXmlApplicationContext 开始的 UML 图-关注 ApplicationContext

重点关注 ApplicationContext ,可以看到它是 Spring 基本功能定义的集大成者

在这里插入图片描述

特性
ClassPathXmlApplicationContext 的特性

以下内容来自于 spring-context-4.3.0-RELEASE.jar org.springframework.context.support.ClassPathXmlApplicationContext

  • 配置文件路径可以是具体地址"/myfiles/context.xml",或者 Ant-style 风格的地址 “/myfiles/*-context.xml”
  • 如果有多个配置路径,后面定义的 bean 会覆盖重写前面文件已经定义的bean.这个特性可以用于提供单独的xml文件对特殊的 bean 进行定义.
  • 加载Spring 配置文件可以使用 org.springframework.context.support.GenericApplicationContext ,从而可以获得更为灵活的配置
  • 和 ClassPathXmlApplicationContext 有类似作用的类还有org.springframework.context.support.FileSystemXmlApplicationContext、org.springframework.web.context.support.XmlWebApplicationContext、
    org.springframework.web.context.support.AbstractRefreshableWebApplicationContext、
    org.springframework.context.annotation.AnnotationConfigApplicationContext,其中AnnotationConfigApplicationContext支持使用注解 @Configuration 将类作为bean 的定义来源
    在这里插入图片描述
源码
比对 ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext
/**ClassPathXmlApplicationContext*/
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
/**FileSystemXmlApplicationContext*/
AbstractApplicationContext ac2 = new FileSystemXmlApplicationContext("spring.xml");		
ClassPathXmlApplicationContext 的构造方法内部逻辑

进入源码可以发现 FileSystemXmlApplicationContext 内部逻辑类似
事实上,不管加载来自哪里,初始化 Spring 容器都需要调用

/**
* Create a new ClassPathXmlApplicationContext, loading the definitions
 * from the given XML file and automatically refreshing the context.
 * @param configLocation resource location
 * @throws BeansException if context creation failed
 */
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
		//注意这里为true
		this(new String[] {configLocation}, true, null);
	}
/**
* Create a new ClassPathXmlApplicationContext with the given parent,
 * loading the definitions from the given XML files.
 * @param configLocations array of resource locations
 * @param refresh whether to automatically refresh the context,
 * loading all bean definitions and creating all singletons.
 * Alternatively, call refresh manually after further configuring the context.
 * @param parent the parent context
 * @throws BeansException if context creation failed
 * @see #refresh()
 */
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
		throws BeansException {
	
	super(parent);
	//将配置文件地址放入数组 
	//AbstractRefreshableConfigApplicationContext.configLocations
	setConfigLocations(configLocations);
	//本场景为true
	if (refresh) {
		//AbstractApplicationContext.refresh(),加载配置文件或刷新配置文件,
		//所有的(non-lazy-init)单例bean要么全部成功,要么全部失败
		refresh();
	}
}
setConfigLocations(configLocations);

将配置文件路径配置放到 数组 configLocations[] 中
因为配置文件可以是多个

/**
 * Set the config locations for this application context.
 * <p>If not set, the implementation may use a default as appropriate.
 */
public void setConfigLocations(String... locations) {
	if (locations != null) {
		Assert.noNullElements(locations, "Config locations must not be null");
		this.configLocations = new String[locations.length];
		for (int i = 0; i < locations.length; i++) {
			this.configLocations[i] = resolvePath(locations[i]).trim();
		}
	}
	else {
		this.configLocations = null;
	}
}
ConfigurableApplicationContext.refresh() 的接口定义

org.springframework.context.ConfigurableApplicationContext.refresh() 的接口方法定义
它的实现位于 org.springframework.context.support.AbstractApplicationContext.refresh()
事实上,所有初始化 Spring 容器的操作都会调用这个 refresh() 方法,下一篇文章我们将详细讲解
用于加载或者刷新来自 XML 文件、properties 文件 或者关系数据库的配置
是一个在开始阶段调用的方法,简单说,其负责加载的(non-lazy-init)单例 bean 要么全部成功,要么全部失败

/**
* Load or refresh the persistent representation of the configuration,
 * which might an XML file, properties file, or relational database schema.
 * <p>As this is a startup method, it should destroy already created singletons
 * if it fails, to avoid dangling resources. In other words, after invocation
 * of that method, either all or no singletons at all should be instantiated.
 * @throws BeansException if the bean factory could not be initialized
 * @throws IllegalStateException if already initialized and multiple refresh
 * attempts are not supported
 */
void refresh() throws BeansException, IllegalStateException;

小饼干:eager class

为了加快加载速度,Spring 允许在整个 jar 文件没有全部加载完毕,而只要其中一个类被调用就将其这个类加载,这个被成为 eager class
An alternative approach would be eager class loading - to load classes into the JVM as soon as they arrive (i.e., invoke java.lang.Classloader.defineClass(…)), without buffering them or waiting for the entire archive to arrive. This allows us quicker access to some of the class files in the archive, and eliminates the need to cache or buffer a copy of the jar file.
http://www.cs.umd.edu/~pugh/java/latex2html/pack/node11.html

默认情况下, allowEagerClassLoading=true,并且对于 “lazy-init” 的bean 同样有效
org.springframework.beans.factory.support.DefaultListableBeanFactory.java

/** Whether to allow eager class loading even for lazy-init beans */
	private boolean allowEagerClassLoading = true;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值