通过DefaultListableBeanFactory加载.xml配置文件学习Spring-IoC容器注册/加载bean的机制(源码走读)...

 

本文参考了https://my.oschina.net/kaywu123/blog/614325?p={{totalPage}}

 

首先看看测试源码结构:

170548_TtXh_3307898.png

就这么简单。一共四个文件,

SimpleMain是项目入口:

SimpleMain.java

package chak;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
import java.io.IOException;

public class SimpleMain {
    public static void main(String[] args) throws IOException {
        ClassPathResource resource = new ClassPathResource("spring-context.xml");
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        reader.loadBeanDefinitions(resource);
        //MyComponent是自己写的测试类
        MyComponent component = factory.getBean("myComponent", MyComponent.class); 
        component.method();
    }
}

MyComponent.java是一个简单的POJO对象,只有一个method()方法打印一串"Hello World"。这里就不列出来了。

logback.xml是日志,方便我们看到运行情况,但是因为我们这里是直接研究源代码,其实要这个日志也没什么用,可以选择无视之。

spring-context.xml是beans的定义文件。是整个spring项目的核心配置文件,虽然在这里它变得异常简单:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd"
       default-lazy-init="true">

    <bean class="chak.MyComponent" name="myComponent"/>

</beans>

仅仅定义了一个bean。

很好,这就是我们要准备的所有代码。然后让我们深入spring内部,看看这个麻雀的五脏是如何运转的。

在开始之前,可以先来一句提纲携领的话总结整个过程: 先注册BeanDefinition,再获取Bean

某种程度上,从这句话里也可以看到ioc的一点影子。大家总说的IoC其实本质上就实现了一个功能,帮我们的应用程序去管理众多的对象(也就是bean),当我们需要用到某一个对象的时候,我们只需要直接跟IoC容器(BeanFactory)拿就可以,而不再关心构造这个bean需要什么依赖。但是为什么IoC可以帮我们去管理bean呢?实际上就是因为我们通过别的手段告诉它要怎样组织一个容器,而这个组织容器的过程,在我们这个简单的Demo里,就是注册BeanDefinition。

好了,我也相信,看完上面那句话你当然还是不清楚Spring的原理,所以下面让我们通过代码来体会这句话到底概括了什么。

SimpleMain.java 中 main()方法第一行:

ClassPathResource resource = new ClassPathResource("spring-context.xml");

利用xml文件名构造了一个ClassPathResource对象,这个资源对象在稍后将作为BeanDefinitionReader解析的根据。

第二行:

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

这里引入了一个关键的对象: DefaultListableBeanFactory。看字面名称,他是一个可枚举(列举)的[Listable],Bean工厂(即IoC容器,Bean容器)[BeanFactory]的默认实现[Default]。而实际上,除了BeanFactory这一支,DefaultListableBeanFactory还有另一条重要的继承线,来自于AliasRegistry实际上主要是BeanDefinitionRegistry。这条线赋予了它可以动态注册BeanDefinition进Factory的功能。

180423_kwDV_3307898.png

有了构造Factory的接口,自然而然会想到的就是谁来使用它呢?又是怎样使用的呢?

接着看main()方法第三行

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

将上面的factory对象拿去构造了一个XmlBeanDefinitionReader实例,而构造函数实际上是这样的:public XmlBeanDefinitionReader(BeanDefinitionRegistry registry)。也就是说这里只用到了DefaultListableBeanFactory的其中一条继承线上的特性——注册BeanDefinition。

在XmlBeanDefinitionReader的构造方法中,我们传进去了一个BeanDefinitionRegistry(同时也是ioc容器本身)。

具体来说,构造方法是这样的:

XmlBeanDefinitionReader.java

/**
 * Create new XmlBeanDefinitionReader for the given bean factory.
 * @param registry the BeanFactory to load bean definitions into,
 * in the form of a BeanDefinitionRegistry//简而言之,传进来的registry就是最终要承载beanDefinition的容器
 */
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
   super(registry);
}

而实际上在实例化过程中做了实事的是父类的构造方法

/**
 * Create a new AbstractBeanDefinitionReader for the given bean factory.
 * <p>If the passed-in bean factory does not only implement the BeanDefinitionRegistry
 * interface but also the ResourceLoader interface, it will be used as default
 * ResourceLoader as well. This will usually be the case for
 * {@link org.springframework.context.ApplicationContext} implementations.
 * <p>If given a plain BeanDefinitionRegistry, the default ResourceLoader will be a
 * {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}.
 * <p>If the passed-in bean factory also implements {@link EnvironmentCapable} its
 * environment will be used by this reader.  Otherwise, the reader will initialize and
 * use a {@link StandardEnvironment}. All ApplicationContext implementations are
 * EnvironmentCapable, while normal BeanFactory implementations are not.
 * @param registry the BeanFactory to load bean definitions into,
 * in the form of a BeanDefinitionRegistry
 * @see #setResourceLoader
 * @see #setEnvironment
 */
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
   Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
   this.registry = registry;

   // Determine ResourceLoader to use.
   if (this.registry instanceof ResourceLoader) {
      this.resourceLoader = (ResourceLoader) this.registry;
   }
   else {//没错,从 DefaultListableBeanFactory类图就可以看出,
         //它并没有继承ResourceLoader接口,所以在這使用
         //默认的PathMatchingResourcePatternResolver作为资源装载器
      this.resourceLoader = new PathMatchingResourcePatternResolver();
   }

   // Inherit Environment if possible
   if (this.registry instanceof EnvironmentCapable) {
      this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
   }
   else {//同样,DefaultListableBeanFactory也没有继承EnvironmentCapable接口,
         //所以这里也使用默认的StandardEnviroment作为环境
      this.environment = new StandardEnvironment();
   }
}

 

初始化到這了就完成了,其实就做了两件事:

  1. 把registry绑定到reader上,作为后续解析出来的beanDefinition的承载器;
  2. 初始化resourceLoader和enviroment,后续才能从环境中读取Resource

然后就是第四行:

reader.loadBeanDefinitions(resource);

也很容易理解,就是从上面我们定义的"spring-context.xml"资源里,解析出定义bean的BeanDefinition实例,并把它保存到reader所绑定的registry里面。

180704_Buyf_3307898.png

通过类图,我们可以看到main()方法第四行所调用的loadBeanDeinitions(resource : Resource) : int 方法是在BeanDefinitionReader中定义的基础方法,入参为定义bean的资源,返回成功加载的beanDefinition的数量。 但是在这里,XmlBeanDefinitionReader没有直接在这个方法里实现加载功能,而是通过定义一个doLoadBeanDefinitions(inputSource : InputSource, resource : Resource) : int方法来为所有这些loadBeanDefinitions(Resource/String/Resource.../String...)装载方法服务——其中就有第四行所用的loadBeanDeinitions(resource : Resource) : int

XmlBeanDefinitionReader.java

/*添加一些资源修饰属性,包括此资源的字符集,
 *编码类型等(虽然在这里最后实际上还是用了默认值)
 */
@Override
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());
   }
   //这里的resourceCurrentlyBeingLoaded是线程变量,
   //用来记录当前线程正在加载的Resource
   Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); 
   if (currentResources == null) {
      currentResources = new HashSet<EncodedResource>(4);
      this.resourcesCurrentlyBeingLoaded.set(currentResources);
   }
   if (!currentResources.add(encodedResource)) {//正在加载的Resource中包含当前资源,说明存在循环import
      throw new BeanDefinitionStoreException(
            "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
   }
   try {
      InputStream inputStream = encodedResource.getResource().getInputStream();
      try {
         InputSource inputSource = new InputSource(inputStream);
         if (encodedResource.getEncoding() != null) {
            inputSource.setEncoding(encodedResource.getEncoding());
         }
         //这里是将资源传给doLoadBeanDefinitions()进行真正的解析,
         //但是笔者很好奇为什么要在这里把一个对象拆开为InputSource和Resource,
         //直接把EncodeResource或者Resource传给下面的方法不就ok了么?
         //总感觉这里这样的写法不够优雅.有哪位同学如果知道这样设计的原因麻烦告知下(mail:mr_djzhu@163.com)
         return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
      }
      finally {
         inputStream.close();
      }
   }
   catch (IOException ex) {
      throw new BeanDefinitionStoreException(
            "IOException parsing XML document from " + encodedResource.getResource(), ex);
   }
   finally {
      currentResources.remove(encodedResource);//加载完成(或者失败)后,从正在加载资源集合中删除当前资源
      if (currentResources.isEmpty()) {
         this.resourcesCurrentlyBeingLoaded.remove();
      }
   }
}

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
      throws BeanDefinitionStoreException {
   try {
      //正如XmlBeanDefinitionReader名字定义的那样,
      //这是一个xml解析器(reader),所以固然要把输入的资源解析成可读的org.w3c.dom.Document 
      //但是这里不打算展开如何得到这个Document的过程,要提醒一下的就是这里的解析不仅仅做了解析xml的工作,
      //还利用DTD或XSD对xml进行了校验.如果有同学深入研究可以注意一下.
      Document doc = doLoadDocument(inputSource, resource);
      //有了document,接下来要做的肯定就是读取它的信息并构造注册beanDefinition
      return registerBeanDefinitions(doc, resource);
   }
   catch (BeanDefinitionStoreException ex) {
      throw ex;
   }
   catch (SAXParseException ex) {
      throw new XmlBeanDefinitionStoreException(resource.getDescription(),
            "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
   }
   catch (SAXException ex) {
      throw new XmlBeanDefinitionStoreException(resource.getDescription(),
            "XML document from " + resource + " is invalid", ex);
   }
   catch (ParserConfigurationException ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
            "Parser configuration exception parsing XML from " + resource, ex);
   }
   catch (IOException ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
            "IOException parsing XML document from " + resource, ex);
   }
   catch (Throwable ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
            "Unexpected exception parsing XML document from " + resource, ex);
   }
}

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
   //获取BeanDefinitionDocumentReader,这里要注意一下别绕晕了,
   //现在这个方法所在类本身是XmlBeanDefinitionDocumentReader,
   //它是一个可以解析xml文件并注册相关definition的类(他可以解析xml资源文件本身得到Document);
   //而BeanDefinitionDocumentReader接口只关心如何解析Document,实例化并注册beanDefinition.
   //从这个角度可以把后者理解成一个简单的工具类.
   //这里用到的是此接口的默认实现DefaultBeanDefinitionDocumentReader
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
   //获取当前registry(IoC)容器已注册的BeanDefinition数量,当前第一次调用肯定就是0
   int countBefore = getRegistry().getBeanDefinitionCount();
   //实例化和注册beanDefinition
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   //获取此次注册新增的beanDefinition数量
   return getRegistry().getBeanDefinitionCount() - countBefore;
}

然后解析Document的接力棒就传到了DefaultBeanDefinitionDocumentReader手中,继续往下看:

作为一个目的单纯的工具类,DefaultBeanDefinitionDocumentReader仅实现了一个DefinitionDocumentReader接口,这个接口也很只是单纯地定义了一个方法:

BeanDefinitionDocumentReader.java

/**
 * SPI for parsing an XML document that contains Spring bean definitions.
 * Used by {@link XmlBeanDefinitionReader} for actually parsing a DOM document.
 * 实际上解析DOM Document的接口
 */
public interface BeanDefinitionDocumentReader {

   /**
    * Read bean definitions from the given DOM document and
    * register them with the registry in the given reader context.
    * @param doc the DOM document
    * @param readerContext the current context of the reader
    * (includes the target registry and the resource being parsed)
    * @throws BeanDefinitionStoreException in case of parsing errors
    */
   void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
         throws BeanDefinitionStoreException;

}

DefaultBeanDefinitionDocumentReader.java

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
   this.readerContext = readerContext;
   logger.debug("Loading bean definitions");
   Element root = doc.getDocumentElement();
   doRegisterBeanDefinitions(root);
}

 
protected void doRegisterBeanDefinitions(Element root) {
   // Any nested <beans> elements will cause recursion in this method. In
   // order to propagate and preserve <beans> default-* attributes correctly,
   // keep track of the current (parent) delegate, which may be null. Create
   // the new (child) delegate with a reference to the parent for fallback purposes,
   // then ultimately reset this.delegate back to its original (parent) reference.
   // this behavior emulates a stack of delegates without actually necessitating one.
   //保留了当前的delegate,实际上在这里就是null
   BeanDefinitionParserDelegate parent = this.delegate; 
   //创建了一个委托类,由它去解析具体的某一个beanDefinition
   this.delegate = createDelegate(getReaderContext(), root, parent);

   //下面的代码主要为<beans>节点的profile属性服务,如果不是<beans>那就跳过此步骤
   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)) {
            if (logger.isInfoEnabled()) {
               logger.info("Skipped XML bean definition file due to specified profiles [" 
               + profileSpec + "] not matching: " + getReaderContext().getResource());
            }
            return;
         }
      }
   }

   preProcessXml(root);//解析前操作,在默认的实现中未做任何事情,如果子类想自定义前置方法,可覆写之
   parseBeanDefinitions(root, this.delegate); //实际解析BeanDefinition
   postProcessXml(root);//解析后操作,在默认的实现中未做任何事情,如果子类想自定义前置方法,可覆写之

   //重置delegate(这里其实感觉有点多此一举,因为delegate本身是private变量,
   //且没有提供任何方法可以set它的值,所以实际上它永远都是null.
   //如有高人看到了如此设计的深意,请赐教mail:mr_djzhu@163.com)
   this.delegate = parent;
}


protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, 
      Element root, BeanDefinitionParserDelegate parentDelegate) {
   //默认的实现选用BeanDefinitionParserDelegate来解析,如果需要自定义的解析器,可覆写此方法
   BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
   delegate.initDefaults(root, parentDelegate);
   return delegate;
}

/**
 * Parse the elements at the root level in the document:
 * "import", "alias", "bean".    //解析root级别(即beans下来的一级)的元素
 * @param root the DOM root element of the document
 */
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;
            //如果是默认的节点则用parseDefaultElement()进行解析,
            //默认的节点包括import,alias,bean和嵌套的beans
            if (delegate.isDefaultNamespace(ele)) {
               parseDefaultElement(ele, delegate);
            }
            else {
               //如果非默认节点,例如<context:annotation-config>,
               //则需要用delegate自带的解析方法来解析
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}

先来看看默认的节点是怎么解析的:

 

DefaultBeanDefinitionDocumentReader.java

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
   if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
      importBeanDefinitionResource(ele);
   }
   else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
      processAliasRegistration(ele);
   }
   //bean节点比较简单,也比较有代表性,下面来详细看看
   else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
      processBeanDefinition(ele, delegate);
   }
   //嵌套的beans节点,递归调用doRegisterBeanDefinitions()来解析它
   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      // recurse
      doRegisterBeanDefinitions(ele);
   }
}


/**
 * Process the given bean element, parsing the bean definition
 * and registering it with the registry.
 * //真正到了解析注册的地方,分三步走:1.解析 2.装饰 3.注册
 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   //1.这里终于解析出了一个BeanDefinitionHolder,里面包含了BeanDefinition的全部信息以及一些冗余信息
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      //2.把上面的bdHolder做一层装饰
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // Register the final decorated instance.
         //3.将装饰过的bdHolder里面的BeanDefinition注册到registry里 
         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));
   }
}

解析注册BeanDefinition的最后三步走,一步一步来看:

 

第一步,解析:

BeanDefinitionParserDelegate.java

/**
 * Parses the supplied {@code <bean>} element. May return {@code null}
 * if there were errors during parse. Errors are reported to the
 * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
 */
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
   return parseBeanDefinitionElement(ele, null);
}

/**
 * Parses the supplied {@code <bean>} element. May return {@code null}
 * if there were errors during parse. Errors are reported to the
 * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
 */
//containingBean指已存在的BeanDeinition,这里是null
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, 
BeanDefinition containingBean) {
   String id = ele.getAttribute(ID_ATTRIBUTE);//获取bean-id
   String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);//获取bean-name

   List<String> aliases = new ArrayList<String>();
   if (StringUtils.hasLength(nameAttr)) {

      //如果采用分割别名方式定义的bean-name属性,在这里把所有的别名解析出来
      String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, 
MULTI_VALUE_ATTRIBUTE_DELIMITERS);
      aliases.addAll(Arrays.asList(nameArr));
   }
   //优先把bean-id属性赋值给beanName,如果没有id则取第一个aliases的值作为beanName
   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) {
      检查beanName和aliases是否跟当前register中已有的beanName冲突,
      //如果不冲突则把其名字记录到this.usedNames : HashSet<String>中
      checkNameUniqueness(beanName, aliases, ele);
   }


   //真正最后解析xml标签内属性的方法就在这里.方法创建了一个Entity用以
   //保存从Document解析出来的BeanDefinition属性,具体方法实现比较直接也比较简单枯燥,
   //这里就点到为止,不再深入这方面的细节.有兴趣的朋友可以自行研究.  
   //总而言之,通过这个方法我们就已经获取了一个BeanDefinition.
   //尽管它叫Abstract-    
   AbstractBeanDefinition beanDefinition 
       = parseBeanDefinitionElement(ele, beanName, containingBean);
   if (beanDefinition != null) {
      //如果<bean>节点没有制定任何id或name属性,下面给他生成一个默认的名字
      if (!StringUtils.hasText(beanName)) {
         try {
            if (containingBean != null) {
               beanName = BeanDefinitionReaderUtils.generateBeanName(
                     beanDefinition, this.readerContext.getRegistry(), true);
            }
            else {
               beanName = this.readerContext.generateBeanName(beanDefinition);
               // Register an alias for the plain bean class name, if still possible,
               // if the generator returned the class name plus a suffix.
               // This is expected for Spring 1.2/2.0 backwards compatibility.
               String beanClassName = beanDefinition.getBeanClassName();
               if (beanClassName != null   
               && beanName.startsWith(beanClassName) 
               && beanName.length() > beanClassName.length() 
               && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                  aliases.add(beanClassName);
               }
            }
            if (logger.isDebugEnabled()) {
               logger.debug("Neither XML 'id' nor 'name' specified - " +
                     "using generated bean name [" + beanName + "]");
            }
         }
         catch (Exception ex) {
            error(ex.getMessage(), ele);
            return null;
         }
      }
      String[] aliasesArray = StringUtils.toStringArray(aliases);
      //拼装BeanDefinitionHolder对象
      return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
   }

   return null;
}

第二步,装饰(省略)

第三步, 注册:

这里又用到了一个工具类:BeanDefinitionReaderUtils,这个类提供了一系列注册dbHolder到registry的静态方法

BeanDefinitionReaderUtils.java

/**
 * Register the given bean definition with the given bean factory.
 * @param definitionHolder the bean definition including name and aliases
 * @param registry the bean factory to register with
 * @throws BeanDefinitionStoreException if registration failed
 */
public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {

   // Register bean definition under primary name.
   String beanName = definitionHolder.getBeanName();
   //看到这里实际上调用的还是registry本身的方法registerBeanDefinition(beanName,beanDefinition). 
   //如果你还记得前面的代码,应该知道我们这里用到的registry是DefaultListableBeanFactory.
   //所以下面又要回到DefaultListableBeanFactory的registerBeanDefinition方法
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

   // Register aliases for bean name, if any.
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String alias : aliases) {
         registry.registerAlias(beanName, alias);
      }
   }
}

 

DefaultListableBeanFactory.java

/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap 
   = new ConcurrentHashMap<String, BeanDefinition>(256);


//---------------------------------------------------------------------
// Implementation of BeanDefinitionRegistry interface
//---------------------------------------------------------------------

@Override
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 {
         ((AbstractBeanDefinition) beanDefinition).validate();
      }
      catch (BeanDefinitionValidationException ex) {
         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
               "Validation of bean definition failed", ex);
      }
   }

   BeanDefinition oldBeanDefinition;
   //先看看map中有没有同名beanDefinition
   oldBeanDefinition = this.beanDefinitionMap.get(beanName);
   if (oldBeanDefinition != null) {
      if (!isAllowBeanDefinitionOverriding()) {//不允许overriding beanDefinition,抛异常
         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
               "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
               "': There is already [" + oldBeanDefinition + "] bound.");
      }
      //判断新的beanDefinition角色值要小于(才合法)旧的beanDefinition(关于角色,还不大了解)
      else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
         // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
         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 + "]");
         }
      }
      //在实现equals方法时,会定义怎样的两个实例是相等的.如果两个beanDefinition不相等,则打一段info日志出来
      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 + "]");
         }
      }
      else {//排除完以上所有情况,认为这样的override是正常的,只打了一段debug日志
         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 {//下面只是一些更细节的操作,本质上就是把beanDefinitino扔进map里,没别的了.
      if (hasBeanCreationStarted()) {
         // Cannot modify startup-time collection elements anymore (for stable iteration)
         synchronized (this.beanDefinitionMap) {
            this.beanDefinitionMap.put(beanName, beanDefinition);
            List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
            updatedDefinitions.addAll(this.beanDefinitionNames);
            updatedDefinitions.add(beanName);
            this.beanDefinitionNames = updatedDefinitions;
            if (this.manualSingletonNames.contains(beanName)) {
               Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
               updatedSingletons.remove(beanName);
               this.manualSingletonNames = updatedSingletons;
            }
         }
      }
      else {
         // Still in startup registration phase
         this.beanDefinitionMap.put(beanName, beanDefinition);
         this.beanDefinitionNames.add(beanName);
         this.manualSingletonNames.remove(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }

   if (oldBeanDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
   }
}

至此,注册阶段完成.在registry(即我们这里的DefaultListableBeanFactory)实例中,已经有从xml读取进来的bean定义--beanDefinition

 

下面开始,main()方法的第五行,从registry中获取bean:

MyComponent component = factory.getBean("myComponent", MyComponent.class); //MyComponent是自己写的测试类

首先看到的是这里调用的方法是由BeanFactory接口定义,AbstractBeanFactory抽象类实现的. 类似实现的方法还有以下几个:

	//---------------------------------------------------------------------
	// Implementation of BeanFactory interface
	//---------------------------------------------------------------------

	@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

	@Override
	public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
		return doGetBean(name, requiredType, null, false);
	}

	@Override
	public Object getBean(String name, Object... args) throws BeansException {
		return doGetBean(name, null, args, false);
	}

会发现,所有的getBean()方法实现最终都是调用了doGetBean()方法,这里是从BeanFactory获取Bean的入口,也即是依赖注入的入口,所以在这里会涉及到Spring-IoC两种不同的Bean构造模式(单例和原型);防止循环定义Bean的判断;定义并保存bean创建状态等。这里我们撇开细节暂且不看,在我们这个简单的main()方法Demo中,只涉及到对一个简单单例Bean的第一次创建。所以,我们忽略细节,看看一个最普通的

bean是怎样被创建出来的:

AbstractBeanFactory.java

 protected <T> T doGetBean(
            final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
            throws BeansException {

        //获取beanName
        final String beanName = transformedBeanName(name);
        Object bean;

        // 获取单例实例
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            //省略代码...

            //通过单例实例sharedInstance获取bean。注意这里有可能是bean本身;
            //也有可能是通过sharedInstance生成的新的bean实例(当sharedInstance时一个FactoryBean的时候)
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            // Fail if we're already creating this bean instance:
            // We're assumably within a circular reference.
            //如果当前目标bean属于正在创建的原型模式的bean,我们认为这是循环定义bean,抛异常
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // Check if bean definition exists in this factory.
            //下面的代码负责判断父beanFactory不为空,且当前factory中没有制定的bean,
            //则将创建bean的工作委托给父beanFactory
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // Not found -> check parent.
                String nameToLookup = originalBeanName(name);
                if (args != null) {
                    // Delegation to parent with explicit args.
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {
                    // No args -> delegate to standard getBean method.
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }

            if (!typeCheckOnly) {
                //把beanName写入alreadyCreated : Set<String>标记为已创建
                markBeanAsCreated(beanName);
            }

            try {
                //A root bean definition represents the merged bean definition that backs
                //a specific bean in a Spring BeanFactory at runtime. It might have been
                //created from multiple original bean definitions that inherit from each other,
                //typically registered as GenericBeanDefinitions.
                //A root bean definition is essentially the 'unified' bean definition view at runtime.
                //以上是javadoc中对RootBeanDefinition的定义:一句话总结就是运行时唯一的beanDefinition。
                //因为我们有可能在彼此为继承关系的若干个BeanFactory中注册多个同名的bean,
                //通过此方法可以对这种情况做一定的处理,此处暂不深入
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                //检查mbd,在当前类的实现当中只判断了对应的bean指向的类不能为abstract
                checkMergedBeanDefinition(mbd, beanName, args);

                // Guarantee initialization of beans that the current bean depends on.
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        //...遍历当前bean,确保所有依赖的bean都被初始化
                    }
                }

                // Create bean instance.
                if (mbd.isSingleton()) {//单例模式,这是我们重点分析的
                    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {//构造一个工厂来生产bean
                        @Override
                        public Object getObject() throws BeansException {
                            try {
                                //实际上最终调用的还是AbstractBeanFactory抽象类中定义的createBean方法
                                //而当前实现此抽象方法的是AbstractAutowireCapableBeanFactory,
                                //下面接着看AbstractAutowireCapableBeanFactory
                                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);
                }

                else if (mbd.isPrototype()) {
                    // It's a prototype -> create a new instance.
                }

                else {
                    String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }
                    try {
                        //省略代码...
                        //当scope既非singleton也非prototype时,做特殊的初始化
                    }
                    catch (IllegalStateException ex) {
                        //省略代码...
                    }
                }
            }
            catch (BeansException ex) {
                //创建失败,将beanName从alreadyCreated去除
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }
    }

AbstractAutowireCapableBeanFactory.java

//---------------------------------------------------------------------
// Implementation of relevant AbstractBeanFactory template methods
//---------------------------------------------------------------------

/**
 * Central method of this class: creates a bean instance,
 * populates the bean instance, applies post-processors, etc.
 * 创建bean实例,调用后置方法的核心入口
 * @see #doCreateBean
 */
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) 
    throws BeanCreationException {
	if (logger.isDebugEnabled()) {
		logger.debug("Creating instance of bean '" + beanName + "'");
	}
	RootBeanDefinition mbdToUse = mbd;

	// Make sure bean class is actually resolved at this point, and
	// clone the bean definition in case of a dynamically resolved Class
	// which cannot be stored in the shared merged bean definition.
	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
		mbdToUse = new RootBeanDefinition(mbd);
		mbdToUse.setBeanClass(resolvedClass);
	}

	// Prepare method overrides.
	//省略代码...
	//准备和校验方法覆盖

	try {
		// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
		//这里主要判断bean有没有配置前置/后置处理器,如果有,则返回一个代理对象
		//resolveBeforeInstantiation的javadoc : Apply before-instantiation post-processors, 
        //resolving whether there is a before-instantiation shortcut for the specified bean.
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
			return bean;
		}
	}
	catch (Throwable ex) {
		throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
				"BeanPostProcessor before instantiation of bean failed", ex);
	}

	//正式创建bean
	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
	if (logger.isDebugEnabled()) {
		logger.debug("Finished creating instance of bean '" + beanName + "'");
	}
	return beanInstance;
}

AbstractAutowireCapableBeanFactory.java

/**
 * Actually create the specified bean. Pre-creation processing has already happened
 * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
 * <p>Differentiates between default bean instantiation, use of a
 * factory method, and autowiring a constructor.
 * 正式创建bean实体,Pre-creation已经在上一个方法中被执行了
 * 这里只处理通过工厂方法或者构造函数创建bean的情况。
 * @param beanName the name of the bean
 * @param mbd the merged bean definition for the bean
 * @param args explicit arguments to use for constructor or factory method invocation
 * @return a new instance of the bean
 * @throws BeanCreationException if the bean could not be created
 * @see #instantiateBean
 * @see #instantiateUsingFactoryMethod
 * @see #autowireConstructor
 */
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
		throws BeanCreationException {

	// Instantiate the bean.
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
		//没有任何缓存,在这里创建bean实例
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
	Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
	mbd.resolvedTargetType = beanType;

	// Allow post-processors to modify the merged bean definition.
	//post-processors处理,如果有定义的话。我们这里没定义,所以忽略
  //忽略代码...

	// Eagerly cache singletons to be able to resolve circular references
	// even when triggered by lifecycle interfaces like BeanFactoryAware.
	//处理循环依赖问题,这里没有这样的情况
	//忽略代码...


	// Initialize the bean instance. //bean实例初始化
	Object exposedObject = bean;
	try {
		//填充beanDefinition中定义的properties到BeanWrapper中
		populateBean(beanName, mbd, instanceWrapper);
		if (exposedObject != null) {
			//Initialize the given bean instance,
			//applying factory callbacks as well as init methods and bean post processors.
			//调用factory回调方法,调用bean post-processors等。这里暂且忽略
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
	}
	catch (Throwable ex) {
		if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex)
           .getBeanName())) {
			throw (BeanCreationException) ex;
		}
		else {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
		}
	}

	//还是循环依赖的问题,代码没跑到这里同样先忽略(这里忽略的东西有点多... 回头得补上)
  //忽略代码...

	// Register bean as disposable.
	//根据不同的scope把创建出来的bean实例放到处理标记为已处理的bean的缓存池。
	//比如这里scope=singletons,则把bean放到当前registry的disposableBeans : Map<String:Object>中
	try {
		registerDisposableBeanIfNecessary(beanName, bean, mbd);
	}
	catch (BeanDefinitionValidationException ex) {
		throw new BeanCreationException(
				mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
	}

	return exposedObject;
}

doCreateBean方法本身非常庞杂,处理了包括创建BeanWrapperpost-processors处理填充properties处理循环依赖等问题。但罗马非一日建成,代码也不需要一天看完,我们暂且刨去一些高级的“细枝末节”,只关注创建beanWrapper的核心方法,其实就只有一个:

instanceWrapper = createBeanInstance(beanName, mbd, args);//真实创建beanWrapper的方法

AbstractAutowireCapableBeanFactory.java

/**
 * Create a new instance for the specified bean, using an appropriate instantiation strategy:
 * factory method, constructor autowiring, or simple instantiation.
 * 创建一个bean实例,可用的实例化策略有:factory method,constructor autowiring
 * 和 simple instantiation.
 * @param beanName the name of the bean
 * @param mbd the bean definition for the bean
 * @param args explicit arguments to use for constructor or factory method invocation
 * @return BeanWrapper for the new instance
 * @see #instantiateUsingFactoryMethod
 * @see #autowireConstructor
 * @see #instantiateBean
 */
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
	// Make sure bean class is actually resolved at this point.
	//获取bean所定义的类
	Class<?> beanClass = resolveBeanClass(mbd, beanName);

	//首先判断指定的类是public,且有public的构造函数
	if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) 
	&& !mbd.isNonPublicAccessAllowed()) {
		throw new BeanCreationException(mbd.getResourceDescription(), beanName,
				"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
	}

	if (mbd.getFactoryMethodName() != null)  {
		//如果beanDefinition中有定义factoryMethod,则按照工厂策略来创建bean,这里显然不是
		return instantiateUsingFactoryMethod(beanName, mbd, args);
	}

	// Shortcut when re-creating the same bean...
	//面对多次创建同一个bean实例,这里会直接通过缓存中的构造方法来创建,这里第一次创建,忽略之...
	//省略代码...

	// 当指定构造方法的入参为非空时,需要从一众构造方法中选择一个,
	//这里我们使用没有入参的默认构造函数,所以也忽略之...
	Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
	if (ctors != null ||
			mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
			mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
		return autowireConstructor(beanName, mbd, ctors, args);
	}

	// No special handling: simply use no-arg constructor.
	//最后是我们需要的,使用没有传入参数的构造方法
	return instantiateBean(beanName, mbd);
}

 AbstractAutowireCapableBeanFactory.java

/**
 * Instantiate the given bean using its default constructor.
 * 使用默认的构造函数创建bean实例
 * @param beanName the name of the bean
 * @param mbd the bean definition for the bean
 * @return BeanWrapper for the new instance
 */
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
	try {
		Object beanInstance;
		final BeanFactory parent = this;
		if (System.getSecurityManager() != null) {//如有必要,做安全校验,这里没有
			beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
				@Override
				public Object run() {
					return getInstantiationStrategy().instantiate(mbd, beanName, parent);
				}
			}, getAccessControlContext());
		}
		else {
			//首先获取了当前registry的实例化策略实例,然后传参进去实例化bean。
			//注意当前registry默认使用的策略是new CglibSubclassingInstantiationStrategy(),
			//而它继承了SimpleInstantiationStrategy类,
            //实际上我们使用的还是SimpleInstantiationStrategy.instantiate()
			//只有在我们需要通过cglib创建代理类时(比如aop机制)才会用到前者
			//这里继续看后者的instantiate()方法
			beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
		}
		//利用创建出来的纯粹bean实例封装成BeanWrapper。
		//可能有同学会好奇,既然有了bean还需要BeanWrapper做什么呢?答案是初始化bean属性。还记得前面的
		BeanWrapper bw = new BeanWrapperImpl(beanInstance);
		initBeanWrapper(bw);
		return bw;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
	}
}
@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
	// Don't override the class with CGLIB if no overrides.
	if (bd.getMethodOverrides().isEmpty()) {//没有override方法
        //注意这里是java.lang.reflect.Constructor,也就是说控制权到了java底层反射机制手中
		Constructor<?> constructorToUse;
		synchronized (bd.constructorArgumentLock) {
			constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
			if (constructorToUse == null) {
				final Class<?> clazz = bd.getBeanClass();//获取BeanDefinition中的Class
				if (clazz.isInterface()) {
                    //如果class是一个借口,那么没戏了,不能用java默认的反射机制来创建实例
					throw new BeanInstantiationException(clazz, "Specified class is an interface");
				}
				try {
					if (System.getSecurityManager() != null) {//有权限控制,那就判断权限
						constructorToUse = AccessController
                        .doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
							@Override
							public Constructor<?> run() throws Exception {
                                //在这里获取无入参的构造方法
								return clazz.getDeclaredConstructor((Class[]) null);
							}
						});
					}
					else {
                        //在这里获取无入参的构造方法
						constructorToUse =	clazz.getDeclaredConstructor((Class[]) null);
					}
					//把构造方法写入BeanDefinition的缓存中,以后再实例化这个bean就可以跳过获取构造方法的步骤了
					bd.resolvedConstructorOrFactoryMethod = constructorToUse;
				}
				catch (Throwable ex) {
					throw new BeanInstantiationException(clazz, "No default constructor found", ex);
				}
			}
		}
		//利用构造方法创建实例。实际上BeanUtils.instantiateClass还可以接受入参,它是这样定义的:
		//public static <T> T instantiateClass(Constructor<T> ctor, Object... args)
		//这里创建的是空参数的实例
		return BeanUtils.instantiateClass(constructorToUse);
	}
	else {
		// Must generate CGLIB subclass.
		//有override方法,就需要通过可供子类覆写的方法instantiateWithMethodInjection来实例化
		//这里子类就是CglibSubclassingInstantiationStrategy
		return instantiateWithMethodInjection(bd, beanName, owner);
	}
}

再往下深入就是BeanUtils.instantiateClass()方法利用java的反射机制创建实例的过程。本文就不再深入了,到这里。我们就把spring创建bean的过程大致地过了一遍。有了这样的一个框架式的印象,如果我们需要深入了解spring的某一个具体特性,就可以再回到某一个代码的细节处,继续研究。这在稍后的文章中会举一些例子来介绍。

 

以上。

转载于:https://my.oschina.net/djzhu/blog/847905

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值