Spring之IoC容器解析(1)
Spring之IoC容器解析(一)
- 简介
- 层级示意图&接口功能介绍
- 原理分析
- 小结
1. 简介
IoC作为Spring的核心功能之一,内部继承体系错综复杂,下面我们来对它剥丝抽茧的分析一波。
首先,从整体上看Spring容器可以分为两大部分:外部容器和内部容器。外部容器指的是ApplicationContext接口的实现类,我们写程序时也可能经常会用到它。内部容器是BeanFactory的实现类,内部调用较多。
2. 层级示意图
1.内部容器层级示意图
位于顶层的HierarchicalBeanFactory,AutowireCapableBeanFactory,ListableBeanFactory接口均继承于BeanFactory。
ok,那大致介绍下这些接口完成或者扩展了什么功能。
1.BeanFactory:定义了最基础的获取bean的方法,以及一些bean的匹配操作(单例模式,类型匹配等)。
2.HierarchicalBeanFactory:扩展了BeanFactory,提供了获取双亲BeanFactory的方法。其实就是让你可以有一个父BeanFactory
3.ListableBeanFactory:同样扩展了BeanFactory,它可以列举出所有bean的实例而非通过客户端给出的bean name一个一个搜索。感觉预加载的时候比较有用。
4.AutowireCapableBeanFactory:从接口定义的方法中可以看出,该接口主要用于自动装配bean,包括创建bean、装配bean的属性、装配bean的依赖、注册bean等一整套流程。该接口对于外部的应用程序而言,几乎不需要使用,其只应用于Spring容器的内部管理,实际上只有内部BeanFactory实现此功能。
5.ConfigurableBeanFactory:提供bean的属性配置功能,需要对bean进行配置的BeanFactory都会实现它。
6.ConfigurableListableBeanFactory:相比于上面,它可以修改bean definition,以及它可以提前实例化以单例模式存在的bean。
7.AbstractBeanFactory:BeanFactory的一个抽象基类,提供了对bean的基本操作。
8.AbstractAutowireCapableBeanFactory:与上面最主要的区别就是实现了默认的bean创建方法createBean()。
9.DefaultListableBeanFactory:第一个可以真正直接拿来用的容器。官方释义,在访问bean前,先注册所有的definition(可能从bean definition配置文件中)。使用预先建立的bean定义元数据对象,从本地的bean definition表(其实就是一个map)中查询bean definition因而将不会花费太多成本。
10.SingletonBeanRegistry:提供单例注册,查询服务。
11.DefaultSingletonBeanRegistry:实现单例与DisposableBean的生命周期管理(创建,维护,销毁)
12.FactoryBeanRegistrySupport:添加工厂方式创建类FactoryBean的支持。
2.外部容器层级示意图
相比于直接扩展自BeanFactory的简单容器,那么实现自ApplicationContext的容器可以称之为高级容器。同时,在以下方面的功能有所加强。
1.支持应用事件,该功能源于ApplicationEventPublisher接口。引入事件机制后,便于bean的管理。
2.资源访问,该特性源于Resource,ResourceLoader。以此,我们可以从不同的地方来获取bean信息。
3.支持不同的信息源,该接口这里没有标出,是源自MessageSource,可以支持国际化,为多语言版本的应用提供支持。
那还是大致介绍一下这些接口以及抽象类的基本功能。
1.ApplicationContext: 首先是一个外部容器的中心接口,提供应用程序的配置。根据官方释意:一个ApplicationContext提供如下功能:
·用来访问应用程序组件的bean factory方法,其继承自ListableBeanFactory。
·能以通用的方式加载文件资源,其继承自ResourceLoader。
·能够向注册的监听器发布事件,其继承自ApplicationEventPublisher。
·能够解析消息,支持国际化,继承自MessageSource。
·继承自父上下文,后代上下文中的Definition将总能获得优先级,这意味着,例如,一个单亲上下文能够被整个应用程序使用,而每个servlet有它自己的孩子上下文,它独立于其他的servlet。
2.ConfigurableApplicationContext:配置和生命周期方法被封装在这里。
3.AbstractApplicationContext:ApplicationContext的基本抽象实现,提供了BeanFactory的后置processor的注册、应用上下文的双亲维护、资源加载的功能。
4.AbstractRefreshableApplicationContext:官方释义,ApplicationContext的基类的实现,其支持多次refreshs,每次创建一个内部bean工厂实例。通常(但不一定),一个上下文将会由一系列的配置定位来驱动,加载bean definations。
5.AbstractRefreshableConfigApplicationContext:主要为配置文件位置的设置提供入口,即实现了setConfigLocation方法。这就提供了不依赖于Spring的且更灵活、通用的配置注入方式。
6.AbstractXmlApplicationContext:ApplicationContext的便利基类的实现。用于提取包含bean definition信息的XML文档,该文档由XmlBeanDefinitionReader负责解释。
7.FileSystemXmlApplicationContext:这是一个简单的,一站式的便利的ApplicationContext的基本实现。
8.ResourceLoader:加载资源(类路径和文件路径)的策略接口,ApplicationContext需要提供此功能来加载资源。
9.ResourcePatternResolver:解释位置模式的策略接口,其扩展自ResourcePatternResolver接口。
3.原理分析
1.内部容器的启动及加载过程
/*
* 可以看到XmlBeanFactroy的代码还是比较简单的,只是初始化了一个用于读取XML形式的BeanDefinition的对象,除此之外并没有太多的操作。
* 因为主要的BeanFactory的基本实现都已经在DefaultListableBeanFactory中完成了。
*/
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
以上可以看出XmlBeanFactory本身并没有做什么,真正扩展的是XmlBeanDefinitionReader,因为它需要去读取XML形式的BeanDefinition,而BeanFactory的基本功能都在DefaultListableBeanFactory中实现了,XmlBeanFactory直接继承过来。
在初始化父容器的过程中,没有什么特别的。
来看下XmlBeanDefinitionReader如何读取BeanDefinition。
//这个的资源形式是要以Resource形式给出的,比如:
//ClassPathResource res = new ClassPathResource("bean.xml");
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
//这里开始没搞明白,为什么用一个ThreadLocal,不过currentResources这个Set应该是用来判断资源是否循环加载的。
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
//获取目标资源经spring包装后的IO流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//进行bean加载的入口
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
//这里remove掉了之前刚加载好的资源应用,因为resourcesCurrentlyBeingLoaded这个东西的意义应该是当前正在被加载的资源,所以,资源加载完后,会从Set中remove掉。
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
在分析doLoadBeanDefinitions()之前,还有其他部分细节在这里说下。比如Set currentResources = this.resourcesCurrentlyBeingLoaded.get(),为何要用ThreadLocal来存这个Set,根据final代码块的执行过程,推测出该Set应该是保存了即将要被加载或者正在被加载的资源。而loadBeanDefinitions()也没用进行额外的多线程安全的控制,所以借助于ThreadLocal,使得如果存在多线程共同加载,那么,各个线程加载各自的资源,避免出现预期被加载的资源在多线程环境下被其他线程覆盖的情况。
那继续说doLoadBeanDefinitions()。
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
//使用标准的JAXP配置的xml解析器从Resource中加载到Document。这里就不展开说明XML内容加载到Document的过程了。
Document doc = doLoadDocument(inputSource, resource);
//根据加载的Document注册Bean definition。
return registerBeanDefinitions(doc, resource);
}
catch
...
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//根据Document的实际类型创建对应的Reader,将Document中的内容读取到BeanDefinition中。
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//获取已注册的bean definition数量
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//返回从resource中成功注册的bean definition数量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
关于BeanDefinition的载入要分为两步,一是讲XML的内容解析到Document,二是讲Document中的内容按照Spring的规定解析成bean。第一步是在DefaultDocumentLoader中完成的,第二步在BeanDefinitionDocumentReader中完成。
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
//从root结点开始解析,将每一个bean都进行注册
protected void doRegisterBeanDefinitions(Element root) {
//实际上真正的解析过程是在BeanDefinitionParserDelegate这个代理中(processBeanDefinition)进行的。
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
//判断XML中的命名空间是否是默认值(http://www.springframework.org/schema/beans)
//命名空间是Spring用来区分bean元素与其他元素。举个例子,比如A1扩展Spring定义了一个元素名为B的元素,A2同样的定义了一个元素名为B的元素,如果没有命名空间加以区分,那Spring是无法将这两个元素区分开来的。
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
return;
}
}
}
//空函数体,可由开发中重写,在真正解析Document前执行
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
//同preProcessXml(root)
postProcessXml(root);
this.delegate = parent;
}
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;
//只有在默认命名空间下的元素的会被SpringIoC容器解析
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//BeanDefinition的封装,若成功返回Holder,则说明解析成功
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 将BeanDefinition注册到容器中
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
BeanDefinitionHolder是BeanDefinition的一个封装,除了包括BeanDefinition之外,还有beanName,aliases(别名)等信息。具体的解析过程在BeanDefinitionParserDelegate中的parseBeanDefinitionElement处执行。
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
//获取bean定义中的id,name,aliase等属性
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
//检查bean的name唯一性,通过一个存有name的Set以及一个存有aliase的Set来进行判断
checkNameUniqueness(beanName, aliases, ele);
}
//对bean的详细解析入口
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
...
}
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
//读取了bean的className,载入到BeanDefinition中,但是没有实例化!
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
//生成所需的BeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//根据XML中定义的内容,对BeanDefinition进行设置。
//包括singleton,lazy-init,autowire,autowire-candidate等等,基本包含了Spring XML的所有属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
//解析其对应的描述信息(description)
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//添加元数据信息
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析构造函数所需参数
parseConstructorArgElements(ele, bd);
//解析bean的一些成员属性,例如map,list,set等
parsePropertyElements(ele, bd);
//解析bean的访问限定符
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch ...
return null;
}
比如,来看一个解析List的成员的过程
public List<Object> parseListElement(Element collectionEle, BeanDefinition bd) {
//获取value的类型
String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
//获取List的元素个数
NodeList nl = collectionEle.getChildNodes();
ManagedList<Object> target = new ManagedList<Object>(nl.getLength());
target.setSource(extractSource(collectionEle));
target.setElementTypeName(defaultElementType);
target.setMergeEnabled(parseMergeAttribute(collectionEle));
parseCollectionElements(nl, target, bd, defaultElementType);
return target;
}
protected void parseCollectionElements(
NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) {
//遍历所有元素结点,判断类型是否为Element
for (int i = 0; i < elementNodes.getLength(); i++) {
Node node = elementNodes.item(i);
if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) {
target.add(parsePropertySubElement((Element) node, bd, defaultElementType));
}
}
}
纵观整个BeanDefinition的载入过程,从XML到Resource,从Resource到Document,从Document到最后的BeanDefinition,最复杂也最重要的,当属最后一步。
从XML到Resource,其实只是从IO流读取一个文件。
从Resource到Document,是按照通用的XML解析方式解析从Resource获得的数据。
从Document到最后的BeanDefinition,需要根据Spring对于bean的规范,将Document中每个对应的bean结点解析出来。这其实是一个比较漫长的过程,我们知道在用XML形式定义的bean中,Spring特有的标签名有好几十个(ref,idref,scope,props…),需要一个一个去判断这些结点名存在与否,在进行相应的解析。我感觉解析过程中比较麻烦的是关于property的解析,这里说麻烦倒也不是说过程麻烦,而是除却基本的数据类型,像List,Map,Set这样的类型,解析他们的函数基本一样,只有一行代码不一样,但又不能使用泛型方法,所以看上去重复的代码量有点多。
BeanDefinition是一个接口,对应于Spring XML配置的标签项,它定义了一系列的函数来设置,获取这些标签值,可以认为它是bean的一个抽象表现,一般用RootBeanDefinition或者ChildBeanDefinition来实现就可以了。
而BeanDefinitionHolder是BeanDefinition的一个封装,同时持有bean的name,aliases(别名)以及BeanDefinition的实例,是在一个bean标签被成功解析后返回的一个Holder。
加载过程告一段落了,继续讲注册的过程。
//仍旧是DefaultBeanDefinitionDocumentReader类
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//从Document中加载到BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//注册BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// 获取bean的name,因为最终注册后是以map的形式来维护bean的
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 如果有别名的话,同样为这些别名与bean构建映射关系
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
来看下bean是如何被注册的。先说明下BeanDefinition默认是在DefaultListableBeanFactory中被注册的。那么也就是说,在DefaultListableBeanFactory中有维护BeanDefinition的对象。
//用beanname与BeanDefinition产生映射关系,以此维护
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
//验证BeanDefinition是否合法构建,主要是检验需要override的方法是否按照规定override
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
//先从map中取一下,看该bean是否已经被注册。
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
//如果该bean不允许被重写,则会抛出异常
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
//Role有三种,ROLE_APPLICATION(0),ROLE_SUPPORT(1),ROLE_INFRASTRUCTURE(2),进入该分支意味着,BeanDefinition的Role会被改变
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
//发出一个警告,告知BeanDefinition会被一个新的不同的BeanDefinition所覆盖。
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
//允许重写该BeanDefinition
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
//把BeanDefinition放到map中去,算是完成注册
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
//检查该factory的bean创建是否开始了
if (hasBeanCreationStarted()) {
//注册过程需要保持数据的一致性,所以用synchronized加锁
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
//新注册一个BeanDefinition,所以list长度+1,它所持有的是所有bean的name
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
//如果单例模式的bean名单中有该bean的name,那么移除掉它。
//意味着,将一个原本是单例模式的bean重新注册成一个普通的bean
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// 仍处于启动阶段,bean还没有开始注册
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
//做的其实是清除key = beanName 的缓存。
//因为oldBeanDefinition如果存在,且执行到了这里也没有抛出异常,说明该BeanDefinition已经被覆盖,缓存需要更新。
//若是单例模式的bean对象Set中包含该beanName,执行到这里说明该BeanDefinition已经从一个单例模式的bean变为了一个普通的bean,所以缓存也需要更新
resetBeanDefinition(beanName);
}
}
到这里,BeanDefinition的注册就完成了一大半了,剩下的部分就是把该BeanDefinition对应的aliases(别名)也分别注册进去,同样也是用一个map来维护,其中key为beanName,value为aliase,这里就不给出代码了。
这里简单说明几个问题:
1.为何hasBeanCreationStarted()为true时,需要进行同步?
先看下hasBeanCreationStarted()做了什么。
// 存的是那些至少被创建了一次的bean的name
private final Set<String> alreadyCreated =
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(256));
protected boolean hasBeanCreationStarted() {
//判断的条件是这个Set是否为空。
return !this.alreadyCreated.isEmpty();
}
//要知道他什么时候为空,我觉得可以先去看下它什么是后不为空,也就是什么时候进行add操作
//该函数在AbstractBeanFactory中,只有在doGetBean(...)中出现过,该操作是将BeanDefinition实例化成想要的bean
protected void markBeanAsCreated(String beanName) {
if (!this.alreadyCreated.contains(beanName)) {
this.alreadyCreated.add(beanName);
clearMergedBeanDefinition(beanName);
}
}
这样也就明确了只有某个bean被实例化后,alreadyCreated集合才有可能不为空。
根据Spring容器初始化的顺序,会先实例化所有的单例模式的bean,按道理讲,实例化后的alreadyCreated一般不为空。但是上面讲的是内部容器,也就是BeanFactory这一分支,不涉及ApplicationContext分支。
public static void main(String[] args) {
Resource resource = new ClassPathResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
boolean s = factory.containsBean("mybean");
}
就像上面这样使用的话,整个流程就是:
加载xml---->解析xml到Document---->解析Document到BeanDefinition---->注册BeanDefinition(知道这个流程后,自己也能写个简单的IoC容器)
并不像外部容易初始化那般复杂。所以该问题留到讲外部容器初始化过程的时候再继续讨论
4.小结
XmlBeanFactory而言,它扩展于DefaultListableBeanFactory,一般的,这种情况下只需要实现该BeanFactory对应的资源读取器Reader,而注册及其他部分,在DefaultListableBeanFactory中已经完成了。
实际上,DefaultListableBeanFactory就是作为Spring内部默认实际使用的BeanFactory而存在的。
对于内部容器初始化,过程并不复杂。就如同上面提到的一样,流程很简单,但是部分操作(bean的注册,BeanDefinition的生成)与外部容器的初始化都是通用的,所以值得关注。尤其是BeanDefinition生成的时候,Spring解析的及其详细,包括作用范围,重写的函数,各种类型成员的解析等等,一个bean所能表示的所有的信息都被解析到BeanDefinition中。
理解有误之处,请大家多多指正。