上篇文章中Spring-IOC源码---创建BeanFactroy我们可以知道Spring初始化的主体就是refresh()
方法,并且找到了创建BeanFactory的地方,也就是obtainFreshBeanFactory
,该方法先判断是否有工厂,最终new了一个BeanFactory的实例DefaultListableBeanFactory
,
protected final void refreshBeanFactory() throws BeansException {
//判断工厂是否存在
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建Bean工厂
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
//解析配置文件并加载bean
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
本篇继续分析bean工厂是怎么将xml等配置文件里的bean实例初始化进工厂的,也就是怎么生成BeanDefinition
的Map的,也就是上面注释的loadBeanDefinitions
。
断点跟进loadBeanDefinitions
方法
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(this.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);
}
首先new了一个XmlBeanDefinitionReader
(这里思考为什么构造方法传入beanFactory?),我们都知道Reader是用来读取文件的,后续是init步骤,重点看最后一行的loadBeanDefinitions,可以观察到AbstractXmlApplicationContext里的loadBeanDefinitions是重载的(以后有时间细聊),我们跟进去看
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
这里可以看到reader.loadBeanDefinitions(configResources)
;reader加载bean通过configResources,可以跟出来configResources就是ClassPathXmlApplicationContext
构造方法的setConfigLocations(configLocations)
;
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
到这里我们可以猜到后续的步骤了(翻阅千山万水后找到了如下源码):那就是解析xml:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
然后就是注册bean:
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
//注册bean,唯一的name
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
//如果bean有别名,循环注册
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
大家可以翻译过来的注释,bean在注册的时候是存在别名的,需要都注册进来。
其中解析完xml获取到bean的id或name后,实例化这个bean的过程就是通过反射实现的,有兴趣可以自己读,本篇不做详细描述,后续我们会再聊的。
梳理一下从创建DefaultListableBeanFactory到加载完Map<String,BeanDefinition>的大致步骤:
DefaultListableBeanFactory—>
AbstractXmlApplicationContext—>
AbstractBeanDefinitionReader—>
XmlBeanDefinitionReader—>
DefaultBeanDefinitionDocumentReader—>
DefaultListableBeanFactory
很显然兜了一圈,包含了十几个方法跟进,思考:为什么这么做呢?直接干不好吗?
到这里我们基本聊完了IOC的bean工厂和bean实例的创建过程,这两个过程中有很多小细节供大家慢慢查阅和实践,一篇文章毕竟不能描述的太细太深入,那样的话既没太大的价值也容易催眠,所以仅做大致的脉络研究。
网友评论