关键步骤
BeanFactory注册涉及到几个关键的的步骤
1、Resource定位:就是找到定义JavaBean信息的xml文件,并将其封装为Resource对象
2、BeanDedefinition载入:把用户定义好的Javabean表示为Ioc容器内部的数据结构
3、注册BeanDefinition到ioc容器
过程分析
分析BeanFactory的创建流程不是简单的去看如何new一个BeanFactory对象,而是看BeanDefinition如何加载到BeanFactory这一过程。
我们通过上一篇文章《Ioc源码分析-ioc容器初始化主流程》可以知道BeanDefinition的注册到BeanFactory是在obtainFreshBeanFactory这个方法中,接下来我们就点进这个方法看一下,他是如何注册的
我们点进这个方法以后就可以看到一个名叫refreshBeanFactory的方法,然后我们看一下这个方法
protected final void refreshBeanFactory() throws BeansException {
// 判断是否已经存在beanFactory
if (hasBeanFactory()) {
// 销毁beans
destroyBeans();
// 关闭工厂
closeBeanFactory();
}
try {
// 实例化DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 设置序列化id
beanFactory.setSerializationId(getId());
// 为beanFactory填充属性
customizeBeanFactory(beanFactory);
// 加载BeanDefinition
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
那么通过上面的方法我们,我们可以看到有一个LodaBeanDefinition方法,加载BeanDefinition,这个应该就是我们要看的方法入口,接着点进去
熟悉源码的同学都知道,在spring源码中,通常实际的执行实现方法通常方法名都会有doXXXX,createXXX等动词开头,所以我们经过依次调用多个类的 loadBeanDefinitions 方法 —> AbstractXmlApplicationContext —>
AbstractBeanDefinitionReader —> XmlBeanDefinitionReader ⼀直执行到
XmlBeanDefinitionReader 的 doLoadBeanDefinitions 方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 解析xml文件,获取document对象
Document doc = doLoadDocument(inputSource, resource);
// 注册BeanDefinition
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
}
同样经过一些重载方法,我们定位到registerBeanDefinition方法
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 获取已有BeanDefinition的个数
int countBefore = getRegistry().getBeanDefinitionCount();
// 注册BeanDefinition
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
这个方法中我们重点关注两个方法,一个是createReaderContexet方法,一个是registerBeanDefinition方法
先看createReaderContext
我们可以看到这个方法初始化了nameSpaceHandler
然后我们再返回去看registerBeanDefinition方法
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
找到doRegisterBeanDefinition方法
protected void doRegisterBeanDefinitions(Element root) {
............
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
这个方法里面我们重点关注parseBeanDefinition方法,perProcessXml前置处理,和PostProcessxml后置处理先不看
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);
}
}
进入parseDefaultElement
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// import元素
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
// alias元素
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
// bean元素
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
// nested元素
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
我们看processBeanDefinition方法解析bean标签
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
.............
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
................
}
我们最后看registerBeanDefinition方法
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
...................
// 判断Bean是否已经存在
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
...........
}
else {
// 判断该bean有没有正在被注册
if (hasBeanCreationStarted()) {
...............
}
// 注册到BeanFactory中
else {
// Still in startup registration phase
// 存放
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
那我们可以看出BeanDefinition注册到BeanFactory中,其实就是把BeanDefinition存放到一个map中
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
时序图