1. 容器的初始化

1. 容器的初始化

Spring IOC


官方定义:

IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies, that is, the other objects they work with, only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse, hence the name Inversion of Control (IoC), of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes, or a mechanism such as the Service Locator pattern.

1. IOC/DI

IoC容器:最主要是完成了完成对象的创建和依赖的管理注入等等。对象和对象关系怎么表示:可以用xml, properties文件等语义化配置文件表示。描述对象关系的文件存放在哪里:可能是classpath, filesystem或者是URL网络资源,servletContext等。

2. 体系结构

2.1 BeanFactory

img

BeanFactory : 作为最顶层的一个接口类,它定义了IOC容器的基本功能规范。

有三个子类:

  • ListableBeanFactory: 表示这些Bean是可列表的
  • HierarchicalBeanFactory:表示的是这些Bean是有继承关系的,也就是每个Bean有可能有父Bean
  • AutowireCapableBeanFactory:定义Bean的自动装配规则

但是从上图中我们可以发现最终的默认实现类是 DefaultListableBeanFactory,他实现了所有的接口。那为何要定义这么多层次的接口呢?查阅这些接口的源码和说明发现,每个接口都有他使用的场合,它主要是为了区分在Spring内部在操作过程中对象的传递和转化过程中,对对象的数据访问所做的限制。

这四个接口共同定义了Bean的集合、Bean之间的关系、以及Bean行为。

BeanFactory里只对IOC容器的基本行为作了定义,根本不关心你的bean是如何定义怎样加载的。正如我们只关心工厂里得到什么的产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心。

public interface BeanFactory {

 Object getBean(String name) throws BeansException;
 <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
 Object getBean(String name, Object... args) throws BeansException;
 <T> T getBean(Class<T> requiredType) throws BeansException;
 boolean containsBean(String name);
 boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
 boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
 boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
 boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

 @Nullable
 Class<?> getType(String name) throws NoSuchBeanDefinitionException;
 String[] getAliases(String name);
}

而要知道工厂是如何产生对象的,我们需要看具体的IOC容器实现,Spring提供了许多IOC容器的实现。

从接口BeanFactoryHierarchicalBeanFactory,再到ConfigurableBeanFactory,是条主要的BeanFactory设计路径。在这条接口设计路径中,BeanFactory接口定义了基本的IoC容器的规范。在这个接口定义中,包括了getBean()这样的IOC容器的基本方法(通过这个方法可以从容器中取得Bean)。而HierarchicalBeanFactory接口在继承了BeanFactory的基本接口之后,增加了getParentBeanFactory的接口功能,使BeanFactory具备了双亲loC容器的管理功能。在接下来的ConfigurableBeanFactory接口中,主要定义了一些对BeanFactory的配置功能,比如通过setParentBeanFactory设置双亲loC容器,通过addBeanPostProcessor()配置Bean后置处理器,等等。通过这些接口设计的叠加,定义了BeanFactory就是简单loC容器的基本功能。关于BeanFactory简单IoC容器的设计,我们会在后面的内容中详细介.

第二条接口设计主线是,以ApplicationContext应用上下文接口为核心的接口设计,这里涉及的主要接口设计有,从BeanFactoryListableBeanFactory, 再到ApplicationContext, 再到我们常用的WebApplicationContext或者ConfigurableApplicationContext接口,我们常用的应用上下文基本上都是ConfigurableApplicationContext或者WebApplicationContext的实现。在这个接口体系中, ListableBeanFactoryHierarchicalBeanFactory两个接口,连接BeanFactory接口 定义和ApplicationConext应用上下文的接口定义,在ListableBeanFactory接口中,细化了许多BeanFactory的接口功能,比如定义了getBeanDefinitionNames接口方法;对于HierarchicalBeanFactory接口,我们在前文中已经提到过;对于ApplicationContext接口,它通过继承MessagesourceResourceloaderApplicationEventPublisher接口,在BeanFactory简单IOC容器的基础上添加了许多高级容器的特性。

这里涉及的是主要接口关系,而具体的IoC容器都是在这个接口体系下实现的,比如DefaultListableBeanFactory,这个基本IoC容器的实现就是实现了ConfigurableBeanFactory,从而成为一个简单IoC容器的实现。像其他IoC容器,比如XmIBeanFactory,都是在DefaultListableBeanFactory的基础上做扩展,同样地ApplicationContext的实现也是如此

这个接口系统是以BeanFactoryApplicationContext为核心的。而BeanFactory又是loC容器的最基本接口,在 ApplicationContext的设计中,一方面,可以看到它继承了BeanFactory接口体系中的ListableBeanFactoryAutowireCapableBeanFactory`` HierarchicalBeanFactoryBeanFactory的接口,具备了BeanFactory IoC容器的基本功能;另一方面,通过继承MessageSourceResourceloadrApplicationEventPublisher这些接口, BeanFactoryApplicationContext赋予了更高级的IoC容器特性。对于ApplicationContext而言,为了在Web环境中使用它,还设计了WebApplicationContext接口,而这个接口通过继承ThemeSource接口来扩充功能。

2.2 BeanDefinition

SpringIOC容器管理了我们定义的各种Bean对象及其相互的关系,Bean对象在Spring实现中是以BeanDefinition来描述的. 其继承体系如下

img

3. IOC 依赖发现的过程

IoC容器的初始化包括BeanDefinitionResource定位、载入和注册这三个基本的过程。 在这里,以ApplciationContext为例。

img

ApplicationContext允许上下文嵌套,通过保持父上下文可以维持一个上下文体系。对于bean的查找可以在这个上下文体系中发生,首先检查当前上下文,其次是父上下文,逐级向上,这样为不同的Spring应用提供了一个共享的bean定义环境。

3.1 XmlBeanFactory的容器创建过程

img

XmlBeanFactory源码

构造方法:

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);
 }
}

3.2 ApplicationContext()IOC容器流程

ApplicationContext提供了许多BeanFctory不具备的功能

  • 支持不同的信息源。我们看到ApplicationContext扩展了MessageSource接口,这些息源的扩展功能可以支持国际化的实现,为开发多语言版本的应用提供服务。
  • 访问资源。这一特性体现在对ResourceLoaderResource的支持上,这样我们可以不同地方得到Bean定义资源。这种抽象使用户程序可以灵活地定义Bean定义信息,尤其是从不同的IO途径得到Bean定义信息。这在接口关系上看不出来,不过一般来说,具体ApplicationContext都是继承了DefaultResourceLoader的子类 DefaultResourceLoaderAbstractApplicationContext的基类,关于ResourceloC容器中的使用,后面会有详细的讲解
  • 支持应用事件。继承了接口ApplicationEventPublisher,从而在上下文中引入了事件机制。这些事件和Bean的生命周期的结合为Bean的管理提供了便利.
  • ApplicationContext中提供的附加服务。这些服务使得基本loC容器的功能更丰富。因为具备了这些丰富的附加功能,使得 ApplicationContext与简单的BeanFactory相对它的使用是一种面向框架的使用风格,所以一般建议在开发应用时ApplicationContext作为IoC容器的基本形式.

我们调用FileSystemXmlApplicationContext

ApplicationContext =new FileSystemXmlApplicationContext(xmlPath);

我们调用FileSystemXmlApplicationContext的构造方法。

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {
 public FileSystemXmlApplicationContext() {
 }

 public FileSystemXmlApplicationContext(ApplicationContext parent) {
  super(parent);
 }

 public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
  this(new String[] {configLocation}, true, null);
 }


  public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
  this(configLocations, true, null);
 }

 public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
  this(configLocations, true, parent);
 }

 public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
  this(configLocations, refresh, null);
 }

 public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
  super(parent);
  setConfigLocations(configLocations);
  if (refresh) refresh();
 }
 protected Resource getResourceByPath(String path) {
  if (path.startsWith("/")) {
   path = path.substring(1);
  }
  return new FileSystemResource(path);
 }
}

他们都在最后通过调用到了:

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
 super(parent);
 setConfigLocations(configLocations);
 if (refresh) refresh();
}
protected Resource getResourceByPath(String path) {
 if (path.startsWith("/")) {
  path = path.substring(1);
 }
 return new FileSystemResource(path);
}

简单来说,IoC容器的初始化是由前面介绍的refresh()方法来启动的,这个方法标志loC容器的正式启动。具体来说,这个启动包括 BeanDefinitionResouce定位、载入和注册三个基本过程。如果我们了解如何编程式地使用IoC容器,就可以清楚地看到Resource定位和载入过程的接口调用。在下面的内容里,我们将会详细分析这三个过程的实现在分析之前,要注意的是, Spring把这三个过程分开,并使用不同的模块完成,如使用相应的Resource LoaderBeanDefinitionReader等模块,通过这样的设计方式来完成, 可以让用户更加灵活地对这三个过程进行剪裁或扩展,定义出最适合自己的oC容器的初始化过程.

  • 第一个过程是Resource定位过程,这个Resource定位指的是BeanDefinition的资源定位,它由Resourceloader通过统一的Resource接口来完成,这个Resource对各种形式的BeanDefinition的使用都提供了统一接口,对于这些BeanDefinition的存在形式,相信大家都不会感到陌生。比如,在文件系统中的Bean定义信息可以使用 FileSystemResource来进行抽象,在类路径中的Bean定义信息可以使用前面提到的ClassPathResource来使用,等等,这个定位过程类似于容器寻找数据的过程,就像用水桶装水先要把水找到一样。

  • 第二个过程是 BeanDefinition的载入,这个载入过程是把用户定义好的Bean表示成loC容器内部的数据结构,而这个容器内部的数据结构就是BeanDefinition,下面介绍这个数据结构的详细定义。具体来说,这个BeanDefinition实际上就是POJO对象在loC容器中的抽象,通过这个BeanDefinition定义的数据结构,使IoC容器能够方便地对POJO对象也就是Bean进行管理。

  • 第三个过程是向IoC容器注册这些BeanDefinition的过程,这个过程是通过调用BeanDefinitionRegistry接口的实现来完成的。这个注册过程把载入过程中解析得到的BeanDefinitionIoC容器进行注册。通过分析,我们可以看到,在IoC容器内部将BeanDefinition注入到一个HashMap中去,IoC容器就是通过这个HashMap来持有这些BeanDefinition数据的.

值得注意的是,这里谈的是1oC容器初始化过程,在这个过程中,一般不包含Bean依赖注入的实现。在 Spring Ioc的设计中,Bean定义的载入和依赖注入是两个独立的过程,依赖注入一般发生在应用第一次通过getBean向容器索取Bean的时候。但有一个例外值得注意,在使用容器时有一个预实例化的配置,通过这个预实例化的配置(具体来说,可以通过为Bean定义信息中的lazyinit属性),用户可以对容器初始化过程作一个微小的控制,从而改变这个被设置了lazyinit属性的Bean的依赖注入过程。举例来说,如果我们对某个Bean设置了lazyinit属性,那么这个Bean的依赖注入在loC容器初始化时就预先完成了,而不需要等到整个初始化完成以后,第一次使用getBean时才会触发了解了IoC容器进行初始化的大致轮廓。

在对象的初始化过程中,调用refresh函数载入beandefinition, 通过分析FileSystemXmlApplicationContext的源代码可以知道,在创建FileSystemXmlApplicationContext容器时,构造方法做以下两项重要工作:

  • 调用父类容器的构造方法(super(parent)方法)为容器设置好Bean资源加载器。
  • 再调用父类AbstractRefreshableConfigApplicationContextsetConfigLocations(configLocations)方法设置Bean定义资源文件的定位路径。

3.2.1 为容器设置Bean资源加载器

通过追踪FileSystemXmlApplicationContext的继承体系,发现AbstractApplicationContext中初始化IoC容器所做的主要源码如下:

public abstract class AbstractApplicationContext extends DefaultResourceLoader
  implements ConfigurableApplicationContext {
    //静态初始化块,在整个容器创建过程中只执行一次  
    static {
    // Eagerly load the ContextClosedEvent class to avoid weird classloader issues
    // on application shutdown in WebLogic 8.1. (Reported by Dustin Woods.)
    ContextClosedEvent.class.getName();
   }
    //AbstractApplicationContext构造方法中调用PathMatchingResourcePatternResolver的构造方法创建Spring资源加载器
   public AbstractApplicationContext() {
    this.resourcePatternResolver = getResourcePatternResolver();
   }
    //FileSystemXmlApplicationContext调用父类构造方法调用的就是该方法  
   public AbstractApplicationContext(@Nullable ApplicationContext parent) {
    this();
    setParent(parent);
   }
  //获取一个Spring Source的加载器用于读入Spring Bean定义资源文件  
    protected ResourcePatternResolver getResourcePatternResolver() {
      return new PathMatchingResourcePatternResolver(this);
    }

    @Override
    public void setParent(@Nullable ApplicationContext parent) {
      this.parent = parent;
      if (parent != null) {
        Environment parentEnvironment = parent.getEnvironment();
        if (parentEnvironment instanceof ConfigurableEnvironment)
          getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
      }
    }
}

3.2.2 设置Bean定义资源文件的定位路径

在设置容器的资源加载器之后,接下来FileSystemXmlApplicationContet执行setConfigLocations方法通过调用其父类AbstractRefreshableConfigApplicationContext的方法进行对Bean定义资源文件的定位,该方法的源码如下:

public void setConfigLocations(@Nullable String... locations) {
  if (locations != null) {
    Assert.noNullElements(locations, "Config locations must not be null");
    this.configLocations = new String[locations.length];
    for (int i = 0; i < locations.length; i++) {
      this.configLocations[i] = resolvePath(locations[i]).trim();
    }
  }
  else {
    this.configLocations = null;
  }
}

  protected String resolvePath(String path) {
    return getEnvironment().resolveRequiredPlaceholders(path);
  }

  public ConfigurableEnvironment getEnvironment() {
    if (this.environment == null) {
      this.environment = createEnvironment();
    }
    return this.environment;
  }
  protected ConfigurableEnvironment createEnvironment() {
    return new StandardEnvironment();
  }

}

至此,Spring IoC容器在初始化时将配置的Bean定义资源文件定位为Spring封装的Resource

3.2.3 refresh函数载入Bean定义过程

在完成对代表BeanDefinitionResource定位的分析后,下面来了解整个BeanDefinition信息的载入过程。对loC容器来说,这个载入过程,相当于把定义的BeanDefinitionloC器中转化成一个Spring内部表示的数据结构的过程。IoC容器对Bean的管理和依赖注入功能的实现,是通过对其持有的BeanDefinition进行各种相关操作来完成的。这些BeanDefinition数据在IoC容器中通过一个HashMap来保持和维护。当然这只是一种比较简单的维护方式如果需要提高loC容器的性能和容量,完全可以自己做一些扩展。

下面,从DefaultListableBeanFactory的设计入手,看看IoC容器是怎样完成BeanDefinition载入的。在开始分析之前,先回到IoC容器的初始化入口,也就是看refresh方法。这个方法的最初是在FileSystemXmlApplicationContext的构造函数中被调用的它的调用标志着容器初始化的开始,这些初始化对象就是BeanDefinition数据初始化入口。

早前放的图可知,这里面的继承顺序: AbstractApplicationContext <- AbstractRefreshableApplicationContext <- AbstractRefreshableConfigApplicationContext <- AbstractXmlApplicationContext <- FileSystemXmlApplicationContext

public void refresh() throws BeansException, IllegalStateException {
  synchronized (this.startupShutdownMonitor) {
    // Prepare this context for refreshing.
    prepareRefresh();

    // Tell the subclass to refresh the internal bean factory.
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

    // Prepare the bean factory for use in this context.
    prepareBeanFactory(beanFactory);

    try {
      // Allows post-processing of the bean factory in context subclasses.
      postProcessBeanFactory(beanFactory);
      // Invoke factory processors registered as beans in the context.
      invokeBeanFactoryPostProcessors(beanFactory);
      // Register bean processors that intercept bean creation.
      registerBeanPostProcessors(beanFactory);
      // Initialize message source for this context.
      initMessageSource();
      // Initialize event multicaster for this context.
      initApplicationEventMulticaster();
      // Initialize other special beans in specific context subclasses.
      onRefresh();
      // Check for listener beans and register them.
      registerListeners();
      // Instantiate all remaining (non-lazy-init) singletons.
      finishBeanFactoryInitialization(beanFactory);
      // Last step: publish corresponding event.
      finishRefresh();
    }
    catch (BeansException ex) {
      if (logger.isWarnEnabled())
        logger.warn("Exception encountered during context initialization - "
          - "cancelling refresh attempt: " + ex);
      // Destroy already created singletons to avoid dangling resources.
      destroyBeans();
      // Reset 'active' flag.
      cancelRefresh(ex);
      // Propagate exception to caller.
      throw ex;
    }
    finally {
      // Reset common introspection caches in Spring's core, since we
      // might not ever need metadata for singleton beans anymore...
      resetCommonCaches();
    }
  }
}

protected void prepareRefresh() {
  this.startupDate = System.currentTimeMillis();
  this.closed.set(false);
  this.active.set(true);
  if (logger.isInfoEnabled())logger.info("Refreshing " + this);

  // Initialize any placeholder property sources in the context environment
  initPropertySources();
  // Validate that all properties marked as required are resolvable
  // see ConfigurablePropertyResolver#setRequiredProperties
  getEnvironment().validateRequiredProperties();
  // Allow for the collection of early ApplicationEvents,
  // to be published once the multicaster is available...
  this.earlyApplicationEvents = new LinkedHashSet<>();
}

Spring IoC容器对Bean定义资源的载入是从refresh()函数开始的,refresh()是一个模板方法,refresh()方法的作用是:在创建IoC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。refresh的作用类似于对IoC容器的重启,再新建立好的容器中对容器进行初始化,对Bean定义资源进行载入。

refresh()方法主要为IoC容器Bean的生命周期管理提供条件,Spring IoC容器载入Bean定义资源文件从其子类容器的refreshBeanFactory()方法启动,所以整个refresh()ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();这句以后代码的都是注册容器的信息源和生命周期事件,载入过程就是从这句代码启动。

3.2.3.1 obtainFreshBeanFactory()方法 刷新容器

AbstractApplicationContext 中实现。

//Tell the subclass to refresh the internal bean factory.
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  //这里使用了委派设计模式,父类定义了抽象的refreshBeanFactory()方法,具体实现调用子类容器的refreshBeanFactory()方法
  refreshBeanFactory();
  ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  if (logger.isDebugEnabled()) {
    logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
  }
  return beanFactory;
}

AbstractRefreshableApplicationContext 中有refreshBeanFactory(). 其中有关闭原来的容器,重建容器。

/**
 * This implementation performs an actual refresh of this context's underlying
 * bean factory, shutting down the previous bean factory (if any) and
 * initializing a fresh bean factory for the next phase of the context's lifecycle.
 */
@Override
protected final void refreshBeanFactory() throws BeansException {
  if (hasBeanFactory()) {
    //Template method for destroying all beans that this context manages.
    destroyBeans();
    closeBeanFactory();
  }
  try {
    DefaultListableBeanFactory beanFactory = createBeanFactory();
    beanFactory.setSerializationId(getId());
    customizeBeanFactory(beanFactory);
    loadBeanDefinitions(beanFactory);
    synchronized (this.beanFactoryMonitor) {
      this.beanFactory = beanFactory;
    }
  }
  catch (IOException ex) {
    throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
  }
}

@Override
protected final void closeBeanFactory() {
  synchronized (this.beanFactoryMonitor) {
    if (this.beanFactory != null)
      this.beanFactory.setSerializationId(null);
      this.beanFactory = null;
  }
}
protected DefaultListableBeanFactory createBeanFactory() {
  return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
  if (this.allowBeanDefinitionOverriding != null) {
    beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
  }
  if (this.allowCircularReferences != null) {
    beanFactory.setAllowCircularReferences(this.allowCircularReferences);
  }
}

在AbstractXmlApplicationContext中调用loadBeanDefinitions()。加载bean。

//Loads the bean definitions via an XmlBeanDefinitionReader.
@Override
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());

  //祖先父类AbstractApplicationContext继承DefaultResourceLoader,因此,容器本身也是一个资源加载器  
  beanDefinitionReader.setResourceLoader(this);
   //为Bean读取器设置SAX xml解析器
  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);
  //Bean读取器真正实现加载的方法  
  loadBeanDefinitions(beanDefinitionReader);
}

//Load the bean definitions with the given XmlBeanDefinitionReader.
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
  Resource[] configResources = getConfigResources();
  if (configResources != null) {
    reader.loadBeanDefinitions(configResources);
  }
  //如果子类中获取的Bean定义资源定位为空,则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源
  String[] configLocations = getConfigLocations();
  if (configLocations != null) {
    reader.loadBeanDefinitions(configLocations);
  }
}

//这里又使用了一个委托模式,调用子类的获取Bean定义资源定位的方法。
//该方法在ClassPathXmlApplicationContext中进行实现,的FileSystemXmlApplicationContext没有使用该方法。
@Nullable
protected Resource[] getConfigResources() {
  return null;
}

这里面调用了XmlBeanDefinitionReader..loadBeanDefinitions(configLocations);由这里,引入了 BeanDefinition读取Bean定义资源。

通过以上对实现原理的分析,我们可以看到,在初始化FileSystmXmlApplicationContext的过程中是通过调用IoC容器的Refresh来启动整个 BeanDefinition的载入过程的,这个初始化是通过定义的XmlBeanDefinitionReader来完成的。同时,我们也知道实际使用的loC容器是 DefultListableBeanFactory,具体的Resource载入在XmlBeanDefinitionReader读入BeanDefinition时实现。因为Spring可以对应不同形式的BeanDefinition。由于这里使用的是XML方式的定义,所以需要使用 XmlBeanDefinitionReader。如果使用了其他的BeanDefinition方式,就需要使用其他种类的BeanDefinitionReader来完成数据的载入工作。 在 XmlBeanDefinitionReader的实现中可以看到,是在reader.loadBeanDefinitions中开始进行BeanDefinition的载入的,而这时 XmlBeanDefinitionReader的父类AbstractBeanDefinitionReader已经为BeanDefinition的载入做好了准备.

3.2.4 BeanDefinition 读取Bean定义资源

3.2.4.1 XmlBeanDefinitionReader读取文件

img

在抽象类AbstractBeanDefinitionReader中定义了 loadBeanDefinitions(String... locations) -> loadBeanDefinitions(String location) -> loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) -> loadBeanDefinitions(resources) -> loadBeanDefinitions(resource) -> loadBeanDefinitions(new EncodedResource(resource)) -> doLoadBeanDefinitions(inputSource, encodedResource.getResource())的路径,找到了文件的路径。

public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable, BeanDefinitionReader {

  public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
  Assert.notNull(locations, "Location array must not be null");
  int counter = 0;
  for (String location : locations) {
   counter += loadBeanDefinitions(location);
  }
  return counter;
 }

  public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
  return loadBeanDefinitions(location, null);
 }
  public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
  ResourceLoader resourceLoader = getResourceLoader();
  if (resourceLoader == null) {
   throw new BeanDefinitionStoreException(
     "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
  }

  if (resourceLoader instanceof ResourcePatternResolver) {
   // Resource pattern matching available.
   try {
    Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
    int loadCount = loadBeanDefinitions(resources);
    if (actualResources != null) {
     for (Resource resource : resources) {
      actualResources.add(resource);
     }
    }
    if (logger.isDebugEnabled()) {
     logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
    }
    return loadCount;
   }
   catch (IOException ex) {
    throw new BeanDefinitionStoreException(
      "Could not resolve bean definition resource pattern [" + location + "]", ex);
   }
  }
  else {
   // Can only load single resources by absolute URL.
   Resource resource = resourceLoader.getResource(location);
   int loadCount = loadBeanDefinitions(resource);
   if (actualResources != null) {
    actualResources.add(resource);
   }
   if (logger.isDebugEnabled()) {
    logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
   }
   return loadCount;
  }
 }

}
3.2.4.2 读取资源转换为Document

这里做了两件事情,第一解析xml文件,同时把bean注册到容器中。 XmlBeanDefinitionReader类中的doLoadBeanDefinitions方法是从特定XML文件中实际载入Bean定义资源的方法,该方法在载入Bean定义资源之后将其转换为Document对象,接下来调用registerBeanDefinitions启动Spring IoC容器对Bean定义的解析过程.

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
        throws BeanDefinitionStoreException {
      try {
        Document doc = doLoadDocument(inputSource, resource);
        return registerBeanDefinitions(doc, resource);
      }
      catch (Exception ex) {
        ...
      }
    }

    protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
    return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
      getValidationModeForResource(resource), isNamespaceAware());
   }
}
3.2.4.3 DocumentLoader解析xml文件

这阶段,是由DocumentLoader的实现类DefaultDocumentLoader具体实现。


public class DefaultDocumentLoader implements DocumentLoader {
  //使用标准的JAXP将载入的Bean定义资源转换成document对象  
 public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
   ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {

//创建文件解析器工厂  
  DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
  if (logger.isDebugEnabled()) {
   logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
  }
    //创建文档解析器  
  DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
    //解析Spring的Bean定义资源  
  return builder.parse(inputSource);
 }

  protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware)
   throws ParserConfigurationException {
//创建文档解析工厂  
  DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  factory.setNamespaceAware(namespaceAware);
      //设置解析XML的校验  
  if (validationMode ! = XmlValidationModeDetector.VALIDATION_NONE) {
   factory.setValidating(true);
   if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {
    // Enforce namespace aware for XSD...
    factory.setNamespaceAware(true);
    try {
     factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
    }
    catch (IllegalArgumentException ex) {
     ParserConfigurationException pcex = new ParserConfigurationException(
       "Unable to validate using XSD: Your JAXP provider [" + factory +
       "] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? " +
       "Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
     pcex.initCause(ex);
     throw pcex;
    }
   }
  }
 }
}
3.2.4.4 XmlBeanDefinitionReader解析载入的Bean定义资源文件

SpringBeanDefinion是怎样按照SpringBean语义要求进行解析并转化为容器内部数据结构的,这个过程是在 registerBeanDefinitions(doc, resource)中完成的。具体的过程是由BeanDefinitionDocumentReader来完成的,这个registerBeanDefinition还对载入的Bean的数量进行了统计。

BeanDefinition的载入分成两部分,首先通过调用XML的解析器得到document对象,但这些documen对象并没有按照SpringBean规则进行解析。在完成通用的XML解析以后,才是照SpringBean规则进行解析的地方,这个按照SpringBean规则进行解析的过程是在documentReader中实现的。这里使用的documentReader是默认设置好的DefaultBeanDefinitionDocumentReader。这个DefaultBeanDefinitionDocumentReader的创建是在后面的方法中完成的,然后再完成BeanDefinition的处理,处理的结果由BeanDefinitionHolder对象来持有这个BeanDefinitionHolder除了持有BeanDefinition对象外,还持有其他与BeanDefinition的使用关的信息,比如Bean的名字、别名集合等。这个BeanDefinitionHolder的生成是通过对Document文档树的内容进行解析来完成的,可以看到这个解析过程是由BeanDefinitionParserDelegate实现(具体在processBeanDefinition方法中实现)的,同时这个解析是与SpringBeanDefinition的配置规则紧密相关的.

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
      BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
      int countBefore = getRegistry().getBeanDefinitionCount();
      documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
      return getRegistry().getBeanDefinitionCount() - countBefore;
    }
    protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
      return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
    }
    private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
}

XmlBeanDefinitionReader中的registerBeanDefinitions方法调用了DefaultBeanDefinitionDocumentReader中的方法 doRegisterBeanDefinitions(Element root)documnet对象进行解析:

具体的SpringBeanDefinition的解析是在BeanDefinitionParserDelegate中完成的。这个类里包含了对各种SpringBean定义规则的处理,感兴趣的读者可以仔细研究。比如我们最熟悉的对Bean元素的处理是怎样完成的,也就是怎样处理在XML定义文件中出现的<bean><bean>这个最常见的元素信息。在这里会看到对那些熟悉的BeanDefinition定义的处理,比如id、name、aliase等属性元素。把这些元素的值从XML文件相应的元素的属性中读取出来以后,设置到生成的BeanDefinitionHolder中去。这些属性的解析还是比较简单的对于其他元素配置的解析,比如各种Bean的属性配置,通过一个较为复杂的解析过程,这个过程是由parseBeanDefinitionElement来完成的。解析完成以后,会把解析结果放到BeanDefinition对象中并设置到BeanDefinitionHolder中去.

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {


  public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    //获得XML描述符
    this.readerContext = readerContext;
    logger.debug("Loading bean definitions");
    //获得Document的根元素  
    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.

  BeanDefinitionParserDelegate parent = this.delegate;
  this.delegate = createDelegate(getReaderContext(), root, parent);

  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;
    }
   }
  }
//在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性  
  preProcessXml(root);
//从Document的根元素开始进行Bean定义的Document对象  
  parseBeanDefinitions(root, this.delegate);
//在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性      
  postProcessXml(root);

  this.delegate = parent;
 }
  //使用Spring的Bean规则从Document的根元素开始进行Bean定义的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;
       if (delegate.isDefaultNamespace(ele)) {
        parseDefaultElement(ele, delegate);
       }
       else {
        delegate.parseCustomElement(ele);
       }
      }
     }
    }
    else {
     delegate.parseCustomElement(root);
    }
   }
//使用Spring的Bean规则解析Document元素节点  
   private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
     importBeanDefinitionResource(ele);
    }
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
     processAliasRegistration(ele);
    }
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
     processBeanDefinition(ele, delegate);
    }
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
     // recurse
     doRegisterBeanDefinitions(ele);
    }
   }

   /**
    * Parse an "import" element and load the bean definitions
    * from the given resource into the bean factory.
    */
   protected void importBeanDefinitionResource(Element ele) {
    String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
    if (!StringUtils.hasText(location)) {
     getReaderContext().error("Resource location must not be empty", ele);
     return;
    }

    // Resolve system properties: e.g. "${user.dir}"
    location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);

    Set<Resource> actualResources = new LinkedHashSet<Resource>(4);

    // Discover whether the location is an absolute or relative URI
    boolean absoluteLocation = false;
    try {
     absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
    }
    catch (URISyntaxException ex) {
     // cannot convert to an URI, considering the location relative
     // unless it is the well-known Spring prefix "classpath*:"
    }

    // Absolute or relative?
    if (absoluteLocation) {
     try {
      int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
      if (logger.isDebugEnabled()) {
       logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
      }
     }
     catch (BeanDefinitionStoreException ex) {
      getReaderContext().error(
        "Failed to import bean definitions from URL location [" + location + "]", ele, ex);
     }
    }
    else {
     // No URL -> considering resource location as relative to the current file.
     try {
      int importCount;
      Resource relativeResource = getReaderContext().getResource().createRelative(location);
      if (relativeResource.exists()) {
       importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
       actualResources.add(relativeResource);
      }
      else {
       String baseLocation = getReaderContext().getResource().getURL().toString();
       importCount = getReaderContext().getReader().loadBeanDefinitions(
         StringUtils.applyRelativePath(baseLocation, location), actualResources);
      }
      if (logger.isDebugEnabled()) {
       logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
      }
     }
     catch (IOException ex) {
      getReaderContext().error("Failed to resolve current resource location", ele, ex);
     }
     catch (BeanDefinitionStoreException ex) {
      getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
        ele, ex);
     }
    }
    Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);
    getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
   }

   /**
    * Process the given alias element, registering the alias with the registry.
    */
   protected void processAliasRegistration(Element ele) {
      ...
   }

   protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
     bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
     try {
      // Register the final decorated instance.
      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));
    }
   }

}

通过以上代码,可以看出: 通过上述Spring IoC容器对载入的Bean定义Document解析可以看出,我们使用Spring时,在Spring配置文件中可以使用<Import>元素来导入IoC容器所需要的其他资源,Spring IoC容器在解析时会首先将指定导入的资源加载进容器中。使用<Ailas>别名时,Spring IoC容器首先将别名元素所定义的别名注册到容器中。 对于既不是<Import>元素,又不是<Alias>元素的元素,即Spring配置文件中普通的<Bean>元素的解析由BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法来实现。

3.2.4.5 BeanDefinitionParserDelegate解析Bean定义资源文件中的元素
/**
 * 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);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
  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) {
    checkNameUniqueness(beanName, aliases, ele);
  }

  AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
  if (beanDefinition != null) {
    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);
    return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
  }

  return null;
}
public AbstractBeanDefinition parseBeanDefinitionElement(
    Element ele, String beanName, BeanDefinition containingBean) {

  this.parseState.push(new BeanEntry(beanName));

  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);
    }
    //根据<Bean>元素配置的class名称和parent属性值创建BeanDefinition  
    //为载入Bean定义信息做准备  
    AbstractBeanDefinition bd = createBeanDefinition(className, parent);  
    //对当前的<Bean>元素中配置的一些属性进行解析和设置,如配置的单态(singleton)属性等  
    parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);  
    //为<Bean>元素解析的Bean设置description信息
    bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));  

    //对<Bean>元素的meta(元信息)属性解析  
    parseMetaElements(ele, bd);  
    //对<Bean>元素的lookup-method属性解析  
    parseLookupOverrideSubElements(ele, bd.getMethodOverrides());  
    //对<Bean>元素的replaced-method属性解析  
    parseReplacedMethodSubElements(ele, bd.getMethodOverrides());  
    //解析<Bean>元素的构造方法设置  

    parseConstructorArgElements(ele, bd);  
    //解析<Bean>元素的<property>设置  
    parsePropertyElements(ele, bd);  
    //解析<Bean>元素的qualifier属性  
    parseQualifierElements(ele, bd);  
    //为当前解析的Bean设置所需的资源和依赖对象  
    bd.setResource(this.readerContext.getResource());  
    bd.setSource(extractSource(ele));

    return bd;
  }
  catch (ClassNotFoundException ex) {
    error("Bean class [" + className + "] not found", ele, ex);
  }
  catch (NoClassDefFoundError err) {
    error("Class that bean class [" + className + "] depends on not found", ele, err);
  }
  catch (Throwable ex) {
    error("Unexpected failure during bean definition parsing", ele, ex);
  }
  finally {
    this.parseState.pop();
  }

  return null;
}

只要使用过Spring,对Spring配置文件比较熟悉的人,通过对上述源码的分析,就会明白我们在Spring配置文件中元素的中配置的属性就是通过该方法解析和设置到Bean中去的。

注意:在解析元素过程中没有创建和实例化Bean对象,只是创建了Bean对象的定义类BeanDefinition,将元素中的配置信息设置到BeanDefinition中作为记录,当依赖注入时才使用这些记录信息创建和实例化具体的Bean对象。

3.2.4.6 BeanDefinitionParserDelegate解析元素
//解析<Bean>元素中的<property>子元素  
   public void parsePropertyElements(Element beanEle, BeanDefinition bd) {  
       //获取<Bean>元素中所有的子元素  
       NodeList nl = beanEle.getChildNodes();  
       for (int i = 0; i < nl.getLength(); i++) {  
           Node node = nl.item(i);  
           //如果子元素是<property>子元素,则调用解析<property>子元素方法解析  
           if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {  
               parsePropertyElement((Element) node, bd);  
           }  
       }  
   }  
   //解析<property>元素  
   public void parsePropertyElement(Element ele, BeanDefinition bd) {  
       //获取<property>元素的名字   
       String propertyName = ele.getAttribute(NAME_ATTRIBUTE);  
       if (!StringUtils.hasLength(propertyName)) {  
           error("Tag 'property' must have a 'name' attribute", ele);  
           return;  
       }  
       this.parseState.push(new PropertyEntry(propertyName));  
       try {  
           //如果一个Bean中已经有同名的property存在,则不进行解析,直接返回。  
           //即如果在同一个Bean中配置同名的property,则只有第一个起作用  
           if (bd.getPropertyValues().contains(propertyName)) {  
               error("Multiple 'property' definitions for property '" + propertyName + "'", ele);  
               return;  
           }  
           //解析获取property的值  
           Object val = parsePropertyValue(ele, bd, propertyName);  
           //根据property的名字和值创建property实例  
           PropertyValue pv = new PropertyValue(propertyName, val);  
           //解析<property>元素中的属性  
           parseMetaElements(ele, pv);  
           pv.setSource(extractSource(ele));  
           bd.getPropertyValues().addPropertyValue(pv);  
       }  
       finally {  
           this.parseState.pop();  
       }  
   }  
   //解析获取property值  
   public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {  
       String elementName = (propertyName != null) ?  
                       "<property> element for property '" + propertyName + "'" :  
                       "<constructor-arg> element";  
       //获取<property>的所有子元素,只能是其中一种类型:ref,value,list等  
       NodeList nl = ele.getChildNodes();  
       Element subElement = null;  
       for (int i = 0; i < nl.getLength(); i++) {  
           Node node = nl.item(i);  
           //子元素不是description和meta属性  
           if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&  
                   !nodeNameEquals(node, META_ELEMENT)) {  
               if (subElement != null) {  
                   error(elementName + " must not contain more than one sub-element", ele);  
               }  
               else {//当前<property>元素包含有子元素  
                   subElement = (Element) node;  
               }  
           }  
       }  
       //判断property的属性值是ref还是value,不允许既是ref又是value  
       boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);  
       boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);  
       if ((hasRefAttribute && hasValueAttribute) ||  
               ((hasRefAttribute || hasValueAttribute) && subElement != null)) {  
           error(elementName +  
                   " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);  
       }  
       //如果属性是ref,创建一个ref的数据对象RuntimeBeanReference,这个对象  
       //封装了ref信息  
       if (hasRefAttribute) {  
           String refName = ele.getAttribute(REF_ATTRIBUTE);  
           if (!StringUtils.hasText(refName)) {  
               error(elementName + " contains empty 'ref' attribute", ele);  
           }  
           //一个指向运行时所依赖对象的引用  
           RuntimeBeanReference ref = new RuntimeBeanReference(refName);  
           //设置这个ref的数据对象是被当前的property对象所引用  
           ref.setSource(extractSource(ele));  
           return ref;  
       }  
        //如果属性是value,创建一个value的数据对象TypedStringValue,这个对象  
       //封装了value信息  
       else if (hasValueAttribute) {  
           //一个持有String类型值的对象  
           TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));  
           //设置这个value数据对象是被当前的property对象所引用  
           valueHolder.setSource(extractSource(ele));  
           return valueHolder;  
       }  
       //如果当前<property>元素还有子元素  
       else if (subElement != null) {  
           //解析<property>的子元素  
           return parsePropertySubElement(subElement, bd);  
       }  
       else {  
           //propery属性中既不是ref,也不是value属性,解析出错返回null        error(elementName + " must specify a ref or value", ele);  
           return null;  
       }  
    }

通过对上述源码的分析,我们可以了解在Spring配置文件中,<Bean>元素中<property>元素的相关配置是如何处理的:

  • ref被封装为指向依赖对象一个引用。
  • value配置都会封装成一个字符串类型的对象。
  • refvalue都通过解析的数据类型属性值.setSource(extractSource(ele));方法将属性值/引用与所引用的属性关联起来。

在方法的最后对于<property>元素的子元素通过parsePropertySubElement方法解析,我们继续分析该方法的源码,了解其解析过程。

3.2.4.7 BeanDefinitionParserDelegate解析元素

BeanDefinitionParserDelegate类中的parsePropertySubElement方法对<property>中的子元素解析:

//解析<property>元素中ref,value或者集合等子元素  
   public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {  
       //如果<property>没有使用Spring默认的命名空间,则使用用户自定义的规则解析//内嵌元素  
       if (!isDefaultNamespace(ele)) {  
           return parseNestedCustomElement(ele, bd);  
       }  
       //如果子元素是bean,则使用解析<Bean>元素的方法解析  
       else if (nodeNameEquals(ele, BEAN_ELEMENT)) {  
           BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);  
           if (nestedBd != null) {  
               nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);  
           }  
           return nestedBd;  
       }  
       //如果子元素是ref,ref中只能有以下3个属性:bean、local、parent  
       else if (nodeNameEquals(ele, REF_ELEMENT)) {  
           //获取<property>元素中的bean属性值,引用其他解析的Bean的名称  
           //可以不再同一个Spring配置文件中,具体请参考Spring对ref的配置规则  
           String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);  
           boolean toParent = false;  
           if (!StringUtils.hasLength(refName)) {  
                //获取<property>元素中的local属性值,引用同一个Xml文件中配置  
                //的Bean的id,local和ref不同,local只能引用同一个配置文件中的Bean  
               refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);  
               if (!StringUtils.hasLength(refName)) {  
                   //获取<property>元素中parent属性值,引用父级容器中的Bean  
                   refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);  
                   toParent = true;  
                   if (!StringUtils.hasLength(refName)) {  
                       error("'bean', 'local' or 'parent' is required for <ref> element", ele);  
                       return null;  
                   }  
               }  
           }  
           //没有配置ref的目标属性值  
           if (!StringUtils.hasText(refName)) {  
               error("<ref> element contains empty target attribute", ele);  
               return null;  
           }  
           //创建ref类型数据,指向被引用的对象  
           RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);  
           //设置引用类型值是被当前子元素所引用  
           ref.setSource(extractSource(ele));  
           return ref;  
       }  
       //如果子元素是<idref>,使用解析ref元素的方法解析  
       else if (nodeNameEquals(ele, IDREF_ELEMENT)) {  
           return parseIdRefElement(ele);  
       }  
       //如果子元素是<value>,使用解析value元素的方法解析  
       else if (nodeNameEquals(ele, VALUE_ELEMENT)) {  
           return parseValueElement(ele, defaultValueType);  
       }  
       //如果子元素是null,为<property>设置一个封装null值的字符串数据  
       else if (nodeNameEquals(ele, NULL_ELEMENT)) {  
           TypedStringValue nullHolder = new TypedStringValue(null);  
           nullHolder.setSource(extractSource(ele));  
           return nullHolder;  
       }  
       //如果子元素是<array>,使用解析array集合子元素的方法解析  
       else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {  
           return parseArrayElement(ele, bd);  
       }  
       //如果子元素是<list>,使用解析list集合子元素的方法解析  
       else if (nodeNameEquals(ele, LIST_ELEMENT)) {  
           return parseListElement(ele, bd);  
       }  
       //如果子元素是<set>,使用解析set集合子元素的方法解析  
       else if (nodeNameEquals(ele, SET_ELEMENT)) {  
           return parseSetElement(ele, bd);  
       }  
       //如果子元素是<map>,使用解析map集合子元素的方法解析  
       else if (nodeNameEquals(ele, MAP_ELEMENT)) {  
           return parseMapElement(ele, bd);  
       }  
       //如果子元素是<props>,使用解析props集合子元素的方法解析  
       else if (nodeNameEquals(ele, PROPS_ELEMENT)) {  
           return parsePropsElement(ele);  
       }  
       //既不是ref,又不是value,也不是集合,则子元素配置错误,返回null  
       else {  
           error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);  
           return null;  
       }  
    }

通过上述源码分析,我们明白了在Spring配置文件中,对<property>元素中配置的ArrayListSetMapProp等各种集合子元素的都通过上述方法解析,生成对应的数据对象,比如ManagedListManagedArrayManagedSet等,这些Managed类是Spring对象BeanDefiniton的数据封装,对集合数据类型的具体解析有各自的解析方法实现,解析方法的命名非常规范,一目了然,我们对<list>集合元素的解析方法进行源码分析,了解其实现过程。

3.2.4.8 解析子元素
//解析<list>集合子元素  
   public List parseListElement(Element collectionEle, BeanDefinition bd) {  
       //获取<list>元素中的value-type属性,即获取集合元素的数据类型  
       String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);  
       //获取<list>集合元素中的所有子节点  
       NodeList nl = collectionEle.getChildNodes();  
       //Spring中将List封装为ManagedList  
       ManagedList<Object> target = new ManagedList<Object>(nl.getLength());  
       target.setSource(extractSource(collectionEle));  
       //设置集合目标数据类型  
       target.setElementTypeName(defaultElementType);  
       target.setMergeEnabled(parseMergeAttribute(collectionEle));  
       //具体的<list>元素解析  
       parseCollectionElements(nl, target, bd, defaultElementType);  
       return target;  
   }   
   //具体解析<list>集合元素,<array>、<list>和<set>都使用该方法解析  
   protected void parseCollectionElements(  
           NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) {  
       //遍历集合所有节点  
       for (int i = 0; i < elementNodes.getLength(); i++) {  
           Node node = elementNodes.item(i);  
           //节点不是description节点  
           if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) {  
               //将解析的元素加入集合中,递归调用下一个子元素  
               target.add(parsePropertySubElement((Element) node, bd, defaultElementType));  
           }  
       }  
    }

经过对Spring Bean定义资源文件转换的Document对象中的元素层层解析,Spring IoC现在已经将XML形式定义的Bean定义资源文件转换为Spring IoC所识别的数据结构——BeanDefinition,它是Bean定义资源文件中配置的POJO对象在Spring IoC容器中的映射,我们可以通过AbstractBeanDefinition为入口, 对IoC容器进行索引、查询和操作。

通过Spring IoC容器对Bean定义资源的解析后,IoC容器大致完成了管理Bean对象的准备工作,即初始化过程,但是最为重要的依赖注入还没有发生,现在在IoC容器中BeanDefinition存储的只是一些静态信息,接下来需要向容器注册Bean定义信息才能全部完成IoC容器的初始化过程.

3.2.5 DefaultListableBeanFactoryIoC容器注册解析后的BeanDefinition

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
      BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
      if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
          // Register the final decorated instance.
          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));
      }
    }
}

在这里 DefaultBeanDefinitionDocumentReader调用了BeanDefinitionReaderUtils.registerBeanDefinition

public static void registerBeanDefinition(
    BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    throws BeanDefinitionStoreException {

  // Register bean definition under primary name.
  String beanName = definitionHolder.getBeanName();
  //向IoC容器注册BeanDefinition
  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);
    }
  }
}
3.2.5.1 DefaultListableBeanFactory向IoC容器注册解析后的BeanDefinition

DefaultListableBeanFactory中使用一个HashMap的集合对象存放IoC容器中注册解析的BeanDefinition,向IoC容器注册的主要源码如下:

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
  implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
      /** Map of bean definition objects, keyed by bean name */
      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 {
          ((AbstractBeanDefinition) beanDefinition).validate();
         }
         catch (BeanDefinitionValidationException ex) {
          throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
            "Validation of bean definition failed", ex);
         }
        }

        BeanDefinition oldBeanDefinition;

        oldBeanDefinition = this.beanDefinitionMap.get(beanName);
        if (oldBeanDefinition != null) {
         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()) {
          // 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 + "]");
          }
         }
         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 {
          if (this.logger.isDebugEnabled()) {
           this.logger.debug("Overriding bean definition for bean '" + beanName +
             "' with an equivalent definition: replacing [" + oldBeanDefinition +
             "] with [" + beanDefinition + "]");
          }
         }
         this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
         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);
        }
      }
}

至此,Bean定义资源文件中配置的Bean被解析过后,已经注册到IoC容器中,被容器管理起来,真正完成了IoC容器初始化所做的全部工作。现 在IoC容器中已经建立了整个Bean的配置信息,这些BeanDefinition信息已经可以使用,并且可以被检索,IoC容器的作用就是对这些注册的Bean定义信息进行处理和维护。这些的注册的Bean定义信息是IoC容器控制反转的基础,正是有了这些注册的数据,容器才可以进行依赖注入。

3.3 总结IOC容器的基本步骤

  1. 初始化的入口在容器实现中的 refresh()调用来完成.
  2. bean 定义载入IOC容器使用的方法是loadBeanDefinition,其中的大致过程如下:
  • 为容器设置Bean资源加载器。AbstractApplicationContext构造方法中调用PathMatchingResourcePatternResolver的构造方法创建Spring资源加载器。

  • 设置Bean定义资源文件的定位路径。

  • refresh函数载入Bean定义过程。

    • obtainFreshBeanFactory()方法 刷新容器.
    • BeanDefinition读取Bean定义资源。读取资源转换为DocumentDocumentLoader解析xml文件。XmlBeanDefinitionReader解析载入的Bean定义资源文件。BeanDefinitionParserDelegate解析Bean定义资源文件中的<Bean>元素。DefaultListableBeanFactoryIoC容器注册解析后的BeanDefinitionDefaultListableBeanFactoryIoC容器注册解析后的BeanDefinition
  • 通过ResourceLoader来完成资源文件位置的定位,DefaultResourceLoader是默认的实现,同时上下文本身就给出了 ResourceLoader的实现,可以从类路径,文件系统, URL等方式来定为资源位置。如果是XmlBeanFactory作为IOC容器,那么需要为它指定bean定义的资源,也就是说bean定义文件时通过抽象成Resource来被IOC容器处理的,容器通过BeanDefinitionReader来完成定义信息的解析和 Bean信息的注册,往往使用的是XmlBeanDefinitionReader来解析beanxml定义文件 - 实际的处理过程是委托给 BeanDefinitionParserDelegate来完成的,从而得到bean的定义信息,这些信息在Spring中使用BeanDefinition对象来表示 - 这个名字可以让我们想到loadBeanDefinition,RegisterBeanDefinition这些相关的方法 - 他们都是为处理BeanDefinitin服务的, 容器解析得到BeanDefinitionIoC以后,需要把它在IOC容器中注册, 这由IOC实现BeanDefinitionRegistry接口来实现。注册过程就是在IOC容器内部维护的一个HashMap来保存得到的BeanDefinition的过程。这个HashMapIoC容器持有bean信息的场所,以后对 bean的操作都是围绕这个HashMap来实现的。

  1. 然后我们就可以通过BeanFactoryApplicationContext来享受到Spring IOC的服务了,在使用IOC容器的时候,我们注意到除了少量粘合代码,绝大多数以正确IoC风格编写的应用程序代码完全不用关心如何到达工厂,因为容器将把这些对象与容器管理的其他对象钩在一起。基本的策略是把工厂放到已知的地方,最好是放在对预期使用的上下文有意义的地方,以及代码将实际需要访问工厂的地方。Spring本身提供了对声明式载入web应用程序用法的应用程序上下文,并将其存储在ServletContext中的框架实现。

BeanfactoryFactory bean,其中BeanFactory指的是IOC容器的编程抽象,比如 ApplicationContextXmlBeanFactory 等,这些都是IOC容器的具体表现,需要使用什么样的容器由客户决定,但Spring为我们提供了丰富的选择。 FactoryBean只是一个可以在IOC而容器中被管理的一个bean,是对各种处理过程和资源使用的抽象,Factory bean在需要时产生另一个对象,而不返回FactoryBean本身,我们可以把它看成是一个抽象工厂,对它的调用返回的是工厂生产的产品。所有的Factory bean都实现特殊的org.springframework.beans.factory.FactoryBean接口,当使用容器中factory bean的时候,该容器不会返回 factory bean本身,而是返回其生成的对象。Spring包括了大部分的通用资源和服务访问抽象的 Factory bean的实现,其中包括:对 JNDI查询的处理,对代理对象的处理,对事务性代理的处理,对RMI代理的处理等,这些我们都可以看成是具体的工厂,看成是SPRING为我们建立好的工厂。也就是说 Spring通过使用抽象工厂模式为我们准备了一系列工厂来生产一些特定的对象,免除我们手工重复的工作,我们要使用时只需要在IOC容器里配置好就能很方便的使用了。

4. IOC 的补充代码

说到这里,我们回到 refresh() 方法,我重新贴了一遍代码,看看我们说到哪了。是的,我们才说完 obtainFreshBeanFactory() 方法。 是的,在浩浩瀚瀚的 refresh() 方法中,我们终于走完了obtainFreshBeanFactory()方法。

考虑到篇幅,这里开始大幅缩减掉没必要详细介绍的部分,大家直接看下面的代码中的注释就好了。

@Override
public void refresh() throws BeansException, IllegalStateException {
   // 来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
   synchronized (this.startupShutdownMonitor) {

      // 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
      prepareRefresh();

      // 这步比较关键,这步完成后,配置文件就会解析成一个个 Bean 定义,注册到 BeanFactory 中,
      // 当然,这里说的 Bean 还没有初始化,只是配置信息都提取出来了,
      // 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map)
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
      // 这块待会会展开说
      prepareBeanFactory(beanFactory);

      try {
         // 【这里需要知道 BeanFactoryPostProcessor 这个知识点,Bean 如果实现了此接口,
         // 那么在容器初始化以后,Spring 会负责调用里面的 postProcessBeanFactory 方法。】

         // 这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化
         // 具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类或做点什么事
         postProcessBeanFactory(beanFactory);
         // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 回调方法
         invokeBeanFactoryPostProcessors(beanFactory);          


         // 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
         // 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
         // 两个方法分别在 Bean 初始化之前和初始化之后得到执行。这里仅仅是注册,之后会看到回调这两方法的时机
         registerBeanPostProcessors(beanFactory);

         // 初始化当前 ApplicationContext 的 MessageSource,国际化这里就不展开说了,不然没完没了了
         initMessageSource();

         // 初始化当前 ApplicationContext 的事件广播器,这里也不展开了
         initApplicationEventMulticaster();

         // 从方法名就可以知道,典型的模板方法(钩子方法),不展开说
         // 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
         onRefresh();

         // 注册事件监听器,监听器需要实现 ApplicationListener 接口。这也不是我们的重点,过
         registerListeners();

         // 重点,重点,重点
         // 初始化所有的 singleton beans
         //(lazy-init 的除外)
         finishBeanFactoryInitialization(beanFactory);

         // 最后,广播事件,ApplicationContext 初始化完成,不展开
         finishRefresh();
      }

      catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }

         // Destroy already created singletons to avoid dangling resources.
         // 销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
         destroyBeans();

         // Reset 'active' flag.
         cancelRefresh(ex);

         // 把异常往外抛
         throw ex;
      }

      finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
      }
   }
}

4.1 准备 Bean 容器: prepareBeanFactory

Spring 把我们在 xml 配置的 bean 都注册以后,会"手动"注册一些特殊的 bean。这里简单介绍下 prepareBeanFactory(factory) 方法:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   // 设置 BeanFactory 的类加载器,我们知道 BeanFactory 需要加载类,也就需要类加载器,
   // 这里设置为加载当前 ApplicationContext 类的类加载器
   beanFactory.setBeanClassLoader(getClassLoader());

   // 设置 BeanExpressionResolver
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
   //
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

   // 添加一个 BeanPostProcessor,这个 processor 比较简单:
   // 实现了 Aware 接口的 beans 在初始化的时候,这个 processor 负责回调,
   // 这个我们很常用,如我们会为了获取 ApplicationContext 而 implement ApplicationContextAware
   // 注意:它不仅仅回调 ApplicationContextAware,
   //   还会负责回调 EnvironmentAware、ResourceLoaderAware 等,看下源码就清楚了
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

   // 下面几行的意思就是,如果某个 bean 依赖于以下几个接口的实现类,在自动装配的时候忽略它们,
   // Spring 会通过其他方式来处理这些依赖。
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

   /**
    * 下面几行就是为特殊的几个 bean 赋值,如果有 bean 依赖了以下几个,会注入这边相应的值,
    * 之前我们说过,"当前 ApplicationContext 持有一个 BeanFactory",这里解释了第一行
    * ApplicationContext 还继承了 ResourceLoader、ApplicationEventPublisher、MessageSource
    * 所以对于这几个依赖,可以赋值为 this,注意 this 是一个 ApplicationContext
    * 那这里怎么没看到为 MessageSource 赋值呢?那是因为 MessageSource 被注册成为了一个普通的 bean
    */
   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
   beanFactory.registerResolvableDependency(ResourceLoader.class, this);
   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
   beanFactory.registerResolvableDependency(ApplicationContext.class, this);

   // 这个 BeanPostProcessor 也很简单,在 bean 实例化后,如果是 ApplicationListener 的子类,
   // 那么将其添加到 listener 列表中,可以理解成:注册 事件监听器
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

   // 这里涉及到特殊的 bean,名为:loadTimeWeaver,这不是我们的重点,忽略它
   // tips: ltw 是 AspectJ 的概念,指的是在运行期进行织入,这个和 Spring AOP 不一样,
   //    感兴趣的读者请参考我写的关于 AspectJ 的另一篇文章 https://www.javadoop.com/post/aspectj
   if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      // Set a temporary ClassLoader for type matching.
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }

   /**
    * 从下面几行代码我们可以知道,Spring 往往很 "智能" 就是因为它会帮我们默认注册一些有用的 bean,
    * 我们也可以选择覆盖
    */

   // 如果没有定义 "environment" 这个 bean,那么 Spring 会 "手动" 注册一个
   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
   }
   // 如果没有定义 "systemProperties" 这个 bean,那么 Spring 会 "手动" 注册一个
   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
   }
   // 如果没有定义 "systemEnvironment" 这个 bean,那么 Spring 会 "手动" 注册一个
   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
   }
}

在这个方法中, Spring 对一些特殊的bean进行的特殊的处理, 也可以理解成Spring 认为这些都是运行环境需要的但是无需使用者自行适配的bean,或者一些Spring的特性功能,可以在这里得到很好的集成。

// TODO

5. 依赖注入的过程

5.1 初始化所有的 singleton beans

我们的重点当然是 finishBeanFactoryInitialization(beanFactory); 这个巨头了,这里会负责初始化所有的singleton beans

注意,后面的描述中,我都会使用初始化或预初始化来代表这个阶段,Spring 会在这个阶段完成所有的 singleton beans 的实例化。

我们来总结一下,到目前为止,应该说 BeanFactory 已经创建完成,并且所有的实现了 BeanFactoryPostProcessor 接口的 Bean 都已经初始化并且其中的 postProcessBeanFactory(factory) 方法已经得到回调执行了。而且 Spring 已经“手动”注册了一些特殊的 Bean,如 ‘environment’、‘systemProperties’ 等。

剩下的就是初始化 singleton beans 了,我们知道它们是单例的,如果没有设置懒加载,那么 Spring 会在接下来初始化所有的 singleton beans。

// 初始化剩余的 singleton beans
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {

   // 首先,初始化名字为 conversionService 的 Bean。本着送佛送到西的精神,我在附录中简单介绍了一下 ConversionService,因为这实在太实用了
   // 什么,看代码这里没有初始化 Bean 啊!
   // 注意了,初始化的动作包装在 beanFactory.getBean(...) 中,这里先不说细节,先往下看吧
   if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
         beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
      beanFactory.setConversionService(
            beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
   }

   // Register a default embedded value resolver if no bean post-processor
   // (such as a PropertyPlaceholderConfigurer bean) registered any before:
   // at this point, primarily for resolution in annotation attribute values.
   if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
         @Override
         public String resolveStringValue(String strVal) {
            return getEnvironment().resolvePlaceholders(strVal);
         }
      });
   }

   // 先初始化 LoadTimeWeaverAware 类型的 Bean
   // 之前也说过,这是 AspectJ 相关的内容,放心跳过吧
   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
   for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
   }

   // Stop using the temporary ClassLoader for type matching.
   beanFactory.setTempClassLoader(null);

   // 没什么别的目的,因为到这一步的时候,Spring 已经开始预初始化 singleton beans 了,
   // 肯定不希望这个时候还出现 bean 定义解析、加载、注册。
   beanFactory.freezeConfiguration();

   // 开始初始化
   beanFactory.preInstantiateSingletons();
}

从上面最后一行往里看,我们就又回到 DefaultListableBeanFactory 这个类了,这个类大家应该都不陌生了吧。

@Override
public void preInstantiateSingletons() throws BeansException {
   if (this.logger.isDebugEnabled()) {
      this.logger.debug("Pre-instantiating singletons in " + this);
   }
   // this.beanDefinitionNames 保存了所有的 beanNames
   List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

   // 触发所有的非懒加载的 singleton beans 的初始化操作
   for (String beanName : beanNames) {

      // 合并父 Bean 中的配置,注意 <bean id="" class="" parent="" /> 中的 parent,用的不多吧,
      // 考虑到这可能会影响大家的理解,我在附录中解释了一下 "Bean 继承",不了解的请到附录中看一下
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

      // 非抽象、非懒加载的 singletons。如果配置了 'abstract = true',那是不需要初始化的
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
         // 处理 FactoryBean(读者如果不熟悉 FactoryBean,请移步附录区了解)
         if (isFactoryBean(beanName)) {
            // FactoryBean 的话,在 beanName 前面加上 ‘&’ 符号。再调用 getBean,getBean 方法别急
            final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
            // 判断当前 FactoryBean 是否是 SmartFactoryBean 的实现,此处忽略,直接跳过
            boolean isEagerInit;
            if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
               isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                  @Override
                  public Boolean run() {
                     return ((SmartFactoryBean<?>) factory).isEagerInit();
                  }
               }, getAccessControlContext());
            }
            else {
               isEagerInit = (factory instanceof SmartFactoryBean &&
                     ((SmartFactoryBean<?>) factory).isEagerInit());
            }
            if (isEagerInit) {

               getBean(beanName);
            }
         }
         else {
            // 对于普通的 Bean,只要调用 getBean(beanName) 这个方法就可以进行初始化了
            getBean(beanName);
         }
      }
   }


   // 到这里说明所有的非懒加载的 singleton beans 已经完成了初始化
   // 如果我们定义的 bean 是实现了 SmartInitializingSingleton 接口的,那么在这里得到回调,忽略
   for (String beanName : beanNames) {
      Object singletonInstance = getSingleton(beanName);
      if (singletonInstance instanceof SmartInitializingSingleton) {
         final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
         if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
               @Override
               public Object run() {
                  smartSingleton.afterSingletonsInstantiated();
                  return null;
               }
            }, getAccessControlContext());
         }
         else {
            smartSingleton.afterSingletonsInstantiated();
         }
      }
   }
}

接下来,我们就进入到 getBean(beanName) 方法了,这个方法我们经常用来从 BeanFactory 中获取一个 Bean,而初始化的过程也封装到了这个方法里。

getBean

在继续前进之前,读者应该具备 FactoryBean 的知识,如果读者还不熟悉,请移步附录部分了解 FactoryBean。

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

// 我们在剖析初始化 Bean 的过程,但是 getBean 方法我们经常是用来从容器中获取 Bean 用的,注意切换思路,
// 已经初始化过了就从容器中直接返回,否则就先初始化再返回
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
      final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
      throws BeansException {
   // 获取一个 “正统的” beanName,处理两种情况,一个是前面说的 FactoryBean(前面带 ‘&’),
   // 一个是别名问题,因为这个方法是 getBean,获取 Bean 用的,你要是传一个别名进来,是完全可以的
   final String beanName = transformedBeanName(name);

   // 注意跟着这个,这个是返回值
   Object bean;

   // 检查下是不是已经创建过了
   Object sharedInstance = getSingleton(beanName);

   // 这里说下 args 呗,虽然看上去一点不重要。前面我们一路进来的时候都是 getBean(beanName),
   // 所以 args 传参其实是 null 的,但是如果 args 不为空的时候,那么意味着调用方不是希望获取 Bean,而是创建 Bean
   if (sharedInstance != null && args == null) {
      if (logger.isDebugEnabled()) {
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.debug("...");
         }
         else {
            logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      // 下面这个方法:如果是普通 Bean 的话,直接返回 sharedInstance,
      // 如果是 FactoryBean 的话,返回它创建的那个实例对象
      // (FactoryBean 知识,读者若不清楚请移步附录)
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

   else {
      if (isPrototypeCurrentlyInCreation(beanName)) {
         // 创建过了此 beanName 的 prototype 类型的 bean,那么抛异常,
         // 往往是因为陷入了循环引用
         throw new BeanCurrentlyInCreationException(beanName);
      }

      // 检查一下这个 BeanDefinition 在容器中是否存在
      BeanFactory parentBeanFactory = getParentBeanFactory();
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
         // 如果当前容器不存在这个 BeanDefinition,试试父容器中有没有
         String nameToLookup = originalBeanName(name);
         if (args != null) {
            // 返回父容器的查询结果
            return (T) parentBeanFactory.getBean(nameToLookup, args);
         }
         else {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
         }
      }

      if (!typeCheckOnly) {
         // typeCheckOnly 为 false,将当前 beanName 放入一个 alreadyCreated 的 Set 集合中。
         markBeanAsCreated(beanName);
      }

      /*
       * 稍稍总结一下:
       * 到这里的话,要准备创建 Bean 了,对于 singleton 的 Bean 来说,容器中还没创建过此 Bean;
       * 对于 prototype 的 Bean 来说,本来就是要创建一个新的 Bean。
       */
      try {
         final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);

         // 先初始化依赖的所有 Bean,这个很好理解。
         // 注意,这里的依赖指的是 depends-on 中定义的依赖
         String[] dependsOn = mbd.getDependsOn();
         if (dependsOn != null) {
            for (String dep : dependsOn) {
               // 检查是不是有循环依赖,这里的循环依赖和我们前面说的循环依赖又不一样,这里肯定是不允许出现的,不然要乱套了,读者想一下就知道了
               if (isDependent(beanName, dep)) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
               }
               // 注册一下依赖关系
               registerDependentBean(dep, beanName);
               // 先初始化被依赖项
               getBean(dep);
            }
         }

         // 如果是 singleton scope 的,创建 singleton 的实例
         if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
               @Override
               public Object getObject() throws BeansException {
                  try {
                     // 执行创建 Bean,详情后面再说
                     return createBean(beanName, mbd, args);
                  }
                  catch (BeansException ex) {
                     destroySingleton(beanName);
                     throw ex;
                  }
               }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }

         // 如果是 prototype scope 的,创建 prototype 的实例
         else if (mbd.isPrototype()) {
            // It's a prototype -> create a new instance.
            Object prototypeInstance = null;
            try {
               beforePrototypeCreation(beanName);
               // 执行创建 Bean
               prototypeInstance = createBean(beanName, mbd, args);
            }
            finally {
               afterPrototypeCreation(beanName);
            }
            bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
         }

         // 如果不是 singleton 和 prototype 的话,需要委托给相应的实现类来处理
         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 {
               Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                  @Override
                  public Object getObject() throws BeansException {
                     beforePrototypeCreation(beanName);
                     try {
                        // 执行创建 Bean
                        return createBean(beanName, mbd, args);
                     }
                     finally {
                        afterPrototypeCreation(beanName);
                     }
                  }
               });
               bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
            }
            catch (IllegalStateException ex) {
               throw new BeanCreationException(beanName,
                     "Scope '" + scopeName + "' is not active for the current thread; consider " +
                     "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                     ex);
            }
         }
      }
      catch (BeansException ex) {
         cleanupAfterBeanCreationFailure(beanName);
         throw ex;
      }
   }

   // 最后,检查一下类型对不对,不对的话就抛异常,对的话就返回了
   if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
      try {
         return getTypeConverter().convertIfNecessary(bean, requiredType);
      }
      catch (TypeMismatchException ex) {
         if (logger.isDebugEnabled()) {
            logger.debug("Failed to convert bean '" + name + "' to required type '" +
                  ClassUtils.getQualifiedName(requiredType) + "'", ex);
         }
         throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
   }
   return (T) bean;
}

在这个方法中,有两个方法尤其重要, 第一个是isDependent(String beanName, String dependentBeanName) 第二个是createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args),这两个方法共同 撑起了整个getBean(String name),第一个让Spring去检查是否有循环依赖,第二个是真正去创建方法。

createBean

@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;

   // 确保 BeanDefinition 中的 Class 被加载
   Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
   if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
      mbdToUse = new RootBeanDefinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
   }

   // 准备方法覆写,这里又涉及到一个概念:MethodOverrides,它来自于 bean 定义中的 <lookup-method />
   // 和 <replaced-method />,如果读者感兴趣,回到 bean 解析的地方看看对这两个标签的解析。
   try {
      mbdToUse.prepareMethodOverrides();
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
            beanName, "Validation of method overrides failed", ex);
   }

   try {
      // 让 InstantiationAwareBeanPostProcessor 在这一步有机会返回代理,
      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;
}

创建 Bean

我们继续往里看 doCreateBean 这个方法:


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) {
      // 说明不是 FactoryBean,这里实例化 Bean,这里非常关键,细节之后再说
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   // 这个就是 Bean 里面的 我们定义的类 的实例,很多地方我直接描述成 "bean 实例"
   final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
   // 类型
   Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
   mbd.resolvedTargetType = beanType;

   // 建议跳过吧,涉及接口:MergedBeanDefinitionPostProcessor
   synchronized (mbd.postProcessingLock) {
      if (!mbd.postProcessed) {
         try {
            // MergedBeanDefinitionPostProcessor,这个我真不展开说了,直接跳过吧,很少用的
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
         }
         catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                  "Post-processing of merged bean definition failed", ex);
         }
         mbd.postProcessed = true;
      }
   }

   // Eagerly cache singletons to be able to resolve circular references
   // even when triggered by lifecycle interfaces like BeanFactoryAware.
   // 下面这块代码是为了解决循环依赖的问题,以后有时间,我再对循环依赖这个问题进行解析吧
   boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
         isSingletonCurrentlyInCreation(beanName));
   if (earlySingletonExposure) {
      if (logger.isDebugEnabled()) {
         logger.debug("Eagerly caching bean '" + beanName +
               "' to allow for resolving potential circular references");
      }
      addSingletonFactory(beanName, new ObjectFactory<Object>() {
         @Override
         public Object getObject() throws BeansException {
            return getEarlyBeanReference(beanName, mbd, bean);
         }
      });
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
      // 这一步也是非常关键的,这一步负责属性装配,因为前面的实例只是实例化了,并没有设值,这里就是设值
      populateBean(beanName, mbd, instanceWrapper);
      if (exposedObject != null) {
         // 还记得 init-method 吗?还有 InitializingBean 接口?还有 BeanPostProcessor 接口?
         // 这里就是处理 bean 初始化完成后的各种回调
         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);
      }
   }

   if (earlySingletonExposure) {
      //
      Object earlySingletonReference = getSingleton(beanName, false);
      if (earlySingletonReference != null) {
         if (exposedObject == bean) {
            exposedObject = earlySingletonReference;
         }
         else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
            String[] dependentBeans = getDependentBeans(beanName);
            Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
            for (String dependentBean : dependentBeans) {
               if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                  actualDependentBeans.add(dependentBean);
               }
            }
            if (!actualDependentBeans.isEmpty()) {
               throw new BeanCurrentlyInCreationException(beanName,
                     "Bean with name '" + beanName + "' has been injected into other beans [" +
                     StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                     "] in its raw version as part of a circular reference, but has eventually been " +
                     "wrapped. This means that said other beans do not use the final version of the " +
                     "bean. This is often the result of over-eager type matching - consider using " +
                     "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
            }
         }
      }
   }

   // Register bean as disposable.
   try {
      registerDisposableBeanIfNecessary(beanName, bean, mbd);
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
   }

   return exposedObject;
}

到这里,我们已经分析完了 doCreateBean 方法,总的来说,我们已经说完了整个初始化流程。

接下来我们挑 doCreateBean 中的三个细节出来说说。一个是创建 Bean 实例的 createBeanInstance 方法,一个是依赖注入的 populateBean 方法,还有就是回调方法 initializeBean。

注意了,接下来的这三个方法要认真说那也是极其复杂的,很多地方我就点到为止了,感兴趣的读者可以自己往里看,最好就是碰到不懂的,自己写代码去调试它。

创建 Bean 实例

我们先看看 createBeanInstance 方法。需要说明的是,这个方法如果每个分支都分析下去,必然也是极其复杂冗长的,我们挑重点说。此方法的目的就是实例化我们指定的类。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
   // 确保已经加载了此 class
   Class<?> beanClass = resolveBeanClass(mbd, beanName);

   // 校验一下这个类的访问权限
   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());
   }

  Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
  if (instanceSupplier != null) {
   return obtainFromSupplier(instanceSupplier, beanName);
  }
   if (mbd.getFactoryMethodName() != null)  {
      // 采用工厂方法实例化,不熟悉这个概念的读者请看附录,注意,不是 FactoryBean
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }

   // 如果不是第一次创建,比如第二次创建 prototype bean。
   // 这种情况下,我们可以从第一次创建知道,采用无参构造函数,还是构造函数依赖注入 来完成实例化
   boolean resolved = false;
   boolean autowireNecessary = false;
   if (args == null) {
      synchronized (mbd.constructorArgumentLock) {
         if (mbd.resolvedConstructorOrFactoryMethod != null) {
            resolved = true;
            autowireNecessary = mbd.constructorArgumentsResolved;
         }
      }
   }
   if (resolved) {
      if (autowireNecessary) {
         // 构造函数依赖注入
         return autowireConstructor(beanName, mbd, null, null);
      }
      else {
         // 无参构造函数
         return instantiateBean(beanName, mbd);
      }
   }

   // 判断是否采用有参构造函数
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   if (ctors != null ||
         mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
      // 构造函数依赖注入
      return autowireConstructor(beanName, mbd, ctors, args);
   }

   // 调用无参构造函数
   return instantiateBean(beanName, mbd);
}

挑个简单的无参构造函数构造实例来看看:

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 {
         // 实例化
         beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
      }
      // 包装一下,返回
      BeanWrapper bw = new BeanWrapperImpl(beanInstance);
      initBeanWrapper(bw);
      return bw;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
   }
}

我们可以看到,关键的地方在于:

beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);

这里会进行实际的实例化过程,我们进去看看:

@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {

   // 如果不存在方法覆写,那就使用 java 反射进行实例化,否则使用 CGLIB,
   // 方法覆写 请参见附录"方法注入"中对 lookup-method 和 replaced-method 的介绍
   if (bd.getMethodOverrides().isEmpty()) {
      Constructor<?> constructorToUse;
      synchronized (bd.constructorArgumentLock) {
         constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
         if (constructorToUse == null) {
            final Class<?> clazz = bd.getBeanClass();
            if (clazz.isInterface()) {
               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);
               }
               bd.resolvedConstructorOrFactoryMethod = constructorToUse;
            }
            catch (Throwable ex) {
               throw new BeanInstantiationException(clazz, "No default constructor found", ex);
            }
         }
      }
      // 利用构造方法进行实例化
      return BeanUtils.instantiateClass(constructorToUse);
   }
   else {
      // 存在方法覆写,利用 CGLIB 来完成实例化,需要依赖于 CGLIB 生成子类,这里就不展开了。
      // tips: 因为如果不使用 CGLIB 的话,存在 override 的情况 JDK 并没有提供相应的实例化支持
      return instantiateWithMethodInjection(bd, beanName, owner);
   }
}

到这里,我们就算实例化完成了。我们开始说怎么进行属性注入。

bean 属性注入

看完了 createBeanInstance(…) 方法,我们来看看 populateBean(…) 方法,该方法负责进行属性设值,处理依赖。

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
   // bean 实例的所有属性都在这里了
   PropertyValues pvs = mbd.getPropertyValues();

   if (bw == null) {
      if (!pvs.isEmpty()) {
         throw new BeanCreationException(
               mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
      }
      else {
         // Skip property population phase for null instance.
         return;
      }
   }

   // 到这步的时候,bean 实例化完成(通过工厂方法或构造方法),但是还没开始属性设值,
   // InstantiationAwareBeanPostProcessor 的实现类可以在这里对 bean 进行状态修改,
   // 我也没找到有实际的使用,所以我们暂且忽略这块吧
   boolean continueWithPropertyPopulation = true;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            // 如果返回 false,代表不需要进行后续的属性设值,也不需要再经过其他的 BeanPostProcessor 的处理
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
               continueWithPropertyPopulation = false;
               break;
            }
         }
      }
   }

   if (!continueWithPropertyPopulation) {
      return;
   }

   if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
         mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

      // 通过名字找到所有属性值,如果是 bean 依赖,先初始化依赖的 bean。记录依赖关系
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
         autowireByName(beanName, mbd, bw, newPvs);
      }

      // 通过类型装配。复杂一些
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
         autowireByType(beanName, mbd, bw, newPvs);
      }

      pvs = newPvs;
   }

   boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
   boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

   if (hasInstAwareBpps || needsDepCheck) {
      PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      if (hasInstAwareBpps) {
         for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
               InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
               // 这里有个非常有用的 BeanPostProcessor 进到这里: AutowiredAnnotationBeanPostProcessor
               // 对采用 @Autowired、@Value 注解的依赖进行设值,这里的内容也是非常丰富的,不过本文不会展开说了,感兴趣的读者请自行研究
               pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
               if (pvs == null) {
                  return;
               }
            }
         }
      }
      if (needsDepCheck) {
         checkDependencies(beanName, mbd, filteredPds, pvs);
      }
   }
   // 设置 bean 实例的属性值
   applyPropertyValues(beanName, mbd, bw, pvs);
}

initializeBean

属性注入完成后,这一步其实就是处理各种回调了,这块代码比较简单。

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
   if (System.getSecurityManager() != null) {
      AccessController.doPrivileged(new PrivilegedAction<Object>() {
         @Override
         public Object run() {
            invokeAwareMethods(beanName, bean);
            return null;
         }
      }, getAccessControlContext());
   }
   else {
      // 如果 bean 实现了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 接口,回调
      invokeAwareMethods(beanName, bean);
   }

   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      // BeanPostProcessor 的 postProcessBeforeInitialization 回调
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   try {
      // 处理 bean 中定义的 init-method,
      // 或者如果 bean 实现了 InitializingBean 接口,调用 afterPropertiesSet() 方法
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }

   if (mbd == null || !mbd.isSynthetic()) {
      // BeanPostProcessor 的 postProcessAfterInitialization 回调
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}