上篇分析了Spring對資源文件的加載過程搂根,接下來我們就要開始分析Spring的IoC容器了(基于XmlBeanFactory)沮明。
1.IoC容器啟動過程簡析
注意:以BeanFactory為基礎的IoC容器在啟動完成之后偶妖,并不會立刻實例化配置文件中的bean,首次實例化發(fā)生在我們第一次向容器索取的過程中肮之。如果IoC容器這個概念生澀難懂瘤袖、或者讓人覺得有些深奧的話衣摩,那么就理解為一個類的實例化即可,只不過這個類的實例化過程捂敌,比較復雜而已艾扮!
在上一篇也介紹了IoC容器的啟動過程為:加載資源文件、解析資源文件占婉、注冊BeanDefinition泡嘴,我們再來看一個更為詳細的流程圖(該流程圖只列舉了比較重要的步驟)。
總而言之逆济,就是將xml文件轉換為SpringIoC容器的內部表示酌予。
2. XmlBeanFactory初始化
打開我們之前復習Spring知識點的測試類,以xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("v2/day01.xml"));
為切入點纹腌。打開XmlBeanFactory類霎终。
public class XmlBeanFactory extends DefaultListableBeanFactory {
// 實例化XmlBeanDefinitionReader對象
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
/**
* 通過指定Resource對象創(chuàng)建XmlBeanFactory實例
*/
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
/**
* 通過指定Resource對象和父BeanFactory創(chuàng)建XmlBeanFactory實例
*/
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
// 依次向上實例化父類構造器
super(parentBeanFactory);
// 解析xml配置文件,將其轉換為IoC容器的內部表示
this.reader.loadBeanDefinitions(resource);
}
}
先來分析加載bean之前的準備工作,XmlBeanFactory父類初始化和XmlBeanDefinitionReader初始化升薯。
2.1 父類初始化
通過XmlBeanFactory的繼承關系依次調用各個父類的構造方法:
flowchat
st=>start: 開始
e=>end: 結束
op1=>operation: 初始化AbstractBeanFactory
op2=>operation: 初始化AbstractAutowireCapableBeanFactory
op3=>operation: 初始化DefaultListableBeanFactory
op4=>operation: 初始化XmlBeanFactory
st->op1->op2->op3->op4->e
該過程初始化的信息很多莱褒,我們選擇其中比較重要的幾點做下介紹。
- 忽略指定接口的自動裝配功能
public AbstractAutowireCapableBeanFactory() {
super();
// 忽略指定接口的自動裝配功能
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
忽略指定接口的自動裝配功能:如ClassA引用了ClassB涎劈,那么當Spring在獲取ClassA的實例時广凸,如果發(fā)現ClassB還沒有被初始化,那么Spring會自動初始化ClassB蛛枚。但是如果ClassB實現了BeanNameAware接口的話谅海,則Spring不會自動初始化ClassB,這就是忽略指定接口的自動裝配蹦浦。
2.2 初始化XmlBeanDefinitionReader
將xml文件中的配置轉換為IoC內部的表示就是由XmlBeanDefinitionReader來完成的扭吁。XmlBeanDefinitionReader繼承了AbstractBeanDefinitionReader類,我們來其初始化都完成了哪些操作。
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
// Determine ResourceLoader to use.
// 1侥袜、確定ResourceLoader使用蝌诡。
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
}
else {
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
// Inherit Environment if possible
// 2、如果環(huán)境可繼承則繼承registry的環(huán)境,否則重新創(chuàng)建環(huán)境
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {
this.environment = new StandardEnvironment();
}
}
- 1枫吧、確定ResourceLoader使用浦旱。該方法的核心就是確定當前使用的類加載器
public PathMatchingResourcePatternResolver() {
this.resourceLoader = new DefaultResourceLoader();
}
public DefaultResourceLoader() {
this.classLoader = ClassUtils.getDefaultClassLoader();
}
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
//優(yōu)先獲取線程上下文類加載器
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back...
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
// 獲取當前類的類加載器
cl = ClassUtils.class.getClassLoader();
if (cl == null) {
// getClassLoader() returning null indicates the bootstrap ClassLoader
try {
//獲取SystemClassLoader
cl = ClassLoader.getSystemClassLoader();
}
catch (Throwable ex) {
// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
}
}
}
return cl;
}
- 2、如果環(huán)境可繼承則繼承registry的環(huán)境,否則重新創(chuàng)建環(huán)境
系統環(huán)境包括了系統環(huán)境屬性(主機變量信息)九杂、JVM系統環(huán)境屬性(JDK版本颁湖,JDK目錄等)、默認激活節(jié)點例隆、屬性解析器等甥捺。
StandardEnvironment初始化
public class StandardEnvironment extends AbstractEnvironment {
/** 系統環(huán)境屬性 System environment property source name: {@value}. */
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
/** JVM系統環(huán)境屬性 JVM system properties property source name: {@value}. */
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
/**
* Customize the set of property sources with those appropriate for any standard
* Java environment:
* <ul>
* <li>{@value #SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME}
* <li>{@value #SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME}
* </ul>
* <p>Properties present in {@value #SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME} will
* take precedence over those in {@value #SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME}.
* @see AbstractEnvironment#customizePropertySources(MutablePropertySources)
* @see #getSystemProperties()
* @see #getSystemEnvironment()
*/
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
// 主要通過System類來獲取信息
// 獲取系統環(huán)境屬性并加入到propertySources中
propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
// 獲取JVM系統環(huán)境屬性并加入到propertySources中
propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}
}
AbstractEnvironment初始化
private final MutablePropertySources propertySources = new MutablePropertySources();
private final ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
public AbstractEnvironment() {
customizePropertySources(this.propertySources);
}