整个流程分为以下三个步骤:
一. XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource(“beans.xml”));
1. 如何查找配置文件
1.1 根据配置文件构建一个 ClassPathResource 对象
A. 配置文件 ClassPathResource 顶级接口类:intputStreamResource 和 Resource
Resource接口抽象了所有的spring内部使用到的底层资源,里面提供了一些抽象方法
譬如说:存在性,可读性,文件名,文件描述信息等。
B. 对于不同来源的资源文件,都对应有相应的Resource 实现。
文件: FileSystemResource
类路径:ClassPathResource
URL资源:URLResource
Byte数组:ByteArrayResource
C. 这是java设计模式里面的策略模式,接口抽象功能,具体的实现交给子类。
不同的子类,实现的算法或者策略不一样。
1.2 配置文件的读取 XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
通过调用 reader.loadBeanDefinitions(resource) 方法加载资源文件
具体过程:
A. 创建文件加载器对象 DocumentLoader documentLoader = new DefaultDocumentLoader();
B. 通过documentLoader 调用如下方法:
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware)
方法参数说明:
inputSource:资源对象
entityResolver:实体解析器,这里是new ResourceEntityResolver(resourceLoader);
validationMode:文件校验模式,这里是xsd校验,值为3
这个模式的获取是通过查看文件是不是包含有DOCType
namespaceAware:命名空间通知,这里是false
返回一个文档对象
B.1 方法第一步:创建一个 DocumentBuilderFactory
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
factory.setValidating(true);
factory.setNamespaceAware(true);
factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
B.2 方法第二步:创建一个 DocumentBuilder
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
DocumentBuilder docBuilder = factory.newDocumentBuilder(); 这里为:DocumentBuilderImpl
docBuilder.setEntityResolver(entityResolver);
docBuilder.setErrorHandler(errorHandler);
B.3 方法第三步:生成文档对象 Document
builder.parse(inputSource);
具体过程:通过类 DOMParser 来解析
domParser.parse(is);
Document doc = domParser.getDocument();
domParser.dropDocumentReferences();
最终通过XIncludeAwareParserConfiguration解析
这里doc的类型为:DeferredDocumentImpl,该类的说明文档为:
The Document interface represents the entire HTML or XML document
Conceptually, it is the root of the document tree, and provides the
primary access to the document's data.
2. 解析及注册BeanDefinitions
return registerBeanDefinitions(doc, resource);
2.1 第一步
创建:BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
BeanDefinitionDocumentReader的作用是:解析包含BeanDefinition xml文件
就一个默认实现:DefaultBeanDefinitionDocumentReader
documentReader有两个成员变量:
private XmlReaderContext readerContext; 为XmlBeanDefinitionReader中的NamespaceHandlerResolver提供配置
private BeanDefinitionParserDelegate delegate; 真正用来解析xml的BeanDefinition的类
2.2 第二步:
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
这里的createReaderContext(resource)的结果为:XmlReaderContext
然后执行: Element root = doc.getDocumentElement(); 获取到文档的跟元素
该方法在CoreDocumentImpl里面
doRegisterBeanDefinitions(root); //注册根元素
再执行parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
这里分情况处理:
A. 默认标签:
import标签:
alias标签:
bean标签:这里只介绍bean标签的处理
beans标签:递归处理
B. 自定义标签:
2.3 bean标签的解析
A. BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
有三个成员变量:
private final BeanDefinition beanDefinition;
private final String beanName;
private final String[] aliases;
通过delegate解析根元素,得到BeanDefinitionHolder对象
该对象已经包含了配置文件中的各种属性了,例如:claas,id,name等
这里会解析:
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
bd.setDescription
parseBeanDefinitionAttributes
parseMetaElements
parseLookupOverrideSubElements
parseReplacedMethodSubElements
parseConstructorArgElements
parsePropertyElements
parseQualifierElements
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
说明:配置的时候不一定会配置beanName,那么会按照默认规则生成一个beanName
说到这里就必须说一个类:BeanDefinition
BeanDefinition 是一个接口,在spring中存在三种实现,RootBeanDefinition,ChildBeanDefinition以及GenericBeanDefinition
BeanDefinition 是配置文件元素标签在容器中的内部表示。
元素标签拥有的class,scope,lazy-init等配置属性,BeanDefinition则提供了beanClass,scope,lazyInit等属性
BeanDefinition 和 元素标签 的属性是一一对应的。
其中RootBeanDefinition是最常用的实现类
spring通过RootBeanDefinition将配置文件中的元素标签配置信息转换为容器的内部表示
并将这些BeanDefinition的信息注册到 BeanDefinitionRegistry中。
spring中的 BeanDefinitionRegistry 就像是spring的内存数据库,主要是以map的形式保存
后续操作直接中 BeanDefinitionRegistry 中读取配置信息。
B. bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
装饰,
C. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
注册:
C.1 注册beanDefinition
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
C.2 注册别名
registry.registerAlias(beanName, alias);
this.aliasMap.put(alias, name);
二. Object bean = factory.getBean(“myBean”);
1. 转换beanName,因为传入的参数可能是别名,也可能是FactoryBean,所以需要解析
1.1 如果是beanName,不需要处理
1.2 如果是 “&beanName”,则去掉&
1.3 如果是别名,则转换为beanName
2. 尝试从缓存加载单例
这里只是尝试加载,如果加载不成功,则再尝试从singtonFactories中加载。
因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,在spring中创建bean的原则是不等
bean完成就会创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建时候需要依赖上一个bean则直接使用ObjectFactory
2.1 从singletonObjects缓存map里面获取,获取到直接返回
2.2 如果获取不到,从singletonFactories缓存的map里面获取到ObjectFactory对象
2.3 从 2.2 中获取到的ObjectFactory对象获取实例:singletonObject = singletonFactory.getObject();
2.4 将获取到的实例放入缓存:this.earlySingletonObjects.put(beanName, singletonObject);
2.5 将 2.2 中获取到的ObjectFactory对象从缓存中移除,this.singletonFactories.remove(beanName);
3. bean的实例化 :bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
从第2步获取的bean,可能是真正的bean,也可能是FactoryBean,
如果是FactoryBean,需要调用getObject()方法来处理
获取到对象之后,object = postProcessObjectFromFactoryBean(object, beanName);
对对象还做了后置处理
4. 原型模式的依赖检查,抛异常
5. 检测parentBeanFactory
如果缓存中找不到,找父类的parentBeanFactory,递归从缓存中加载bean,加载到直接返回
如果加载不到,或者parentBeanFactory不存在,则从头开始加载bean
6. 将xml配置文件的GenericBeanDefinition 转换为RootBeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
7. 寻找依赖
解决循环依赖的问题:registerDependentBean(dep, beanName);
8. 针对不同的scope进行bean的创建
单例创建:
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
原型创建:略去
其他scope创建:略去
9. 类型转换