Spring IOC流程源码分析

一、Spring 核心容器 IOC初始化过程

  1. Spring 核心之 IOC 容器初体验
  • IOC 与 DI

IOC(Inversion of Control)控制反转:所谓控制反转,就是把原先我们代码里面需要实现的对象创建,依赖的代码,反转给容器来帮忙实现。 那么必然的我们需要创建一个容器 ,同时需要一种描述来让容器知道需要创建的对象与对象的关系。这个描述最具体表现就是我们所看到的配置文件。 DI(Dependency Injection)依赖注入:就是指对象是被动接受依赖类而不是自己主动去找,换句话说就是指对象不是从容器中查找它依赖的类而是在容器实例化对象的时候主动将它依赖的类注入给它。

先从我们自己设计这样一个视角来考虑:

  • 对象和对象的关系怎么表示?

可以用 xml,properties 文件等语义化配置文件表示。

  • 描述对象关系的文件存放在哪里?

可能是 classpath,filesystem,或者是 URL 网络资源,servletContext 等。

  • 不同的配置文件对对象的描述不一样,如标准的,自定义声明式的,如何统一?

在内部需要有一个统一的关于对象的定义,所有外部的描述都必须转化成统一的描述定义。

  • 如何对不同的配置文件进行解析?

需要对不同的配置文件语法,采用不同的解析器。

  1. Spring 核心容器类图
  • BeanFactory
    Spring Bean 的创建是典型的工厂模式,这一系列的 Bean 工厂,也即 IOC 容器为开发者管理对象间的依赖关系提供了很多便利和基础服务,在 Spring 中有许多的 IOC 容器的实现供用户选择和使用,其相互关系如下:
    在这里插入图片描述
    其中 BeanFactory(可以理解为一个HashMap) 作为最顶层的一个接口类,它定义了 IOC 容器的基本功能规范,BeanFactory 有三个重要的子类:ListableBeanFactory、HierarchicalBeanFactory 和 AutowireCapableBeanFactory。

但是从类图中我们可以发现最终的默认实现类是 DefaultListableBeanFactory,它实现了所有的接口。 那为何要定义这么多层次的接口呢?查阅这些接口的源码和说明发现,每个接口都有它使用的场合,它主要是为了区分在 Spring 内部在操作过程中对象的传递和转化过程时,对对象的数据访问所做的限制。例如 ListableBeanFactory 接口表示这些 Bean 是可列表化的,而 HierarchicalBeanFactory 表示的是这些 Bean 是有继承关系的,也就是每个 Bean 有可能有父 Bean。AutowireCapableBeanFactory 接口定义 Bean 的自动装配规则。这三个接口共同定义了 Bean 的集合、Bean 之间的关系、以及 Bean 行为。最基本的 IOC 容器接口 BeanFactory,来看一下它的源码:

public interface BeanFactory {
   //对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
   //如果需要得到工厂本身,需要转义
   String FACTORY_BEAN_PREFIX = "&";
   //根据bean的名字,获取在IOC容器中得到bean实例
   Object getBean(String name) throws BeansException;
   //根据bean的名字和Class类型来得到bean实例,增加了类型安全验证机制。
   <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;
   <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
   //提供对bean的检索,看看是否在IOC容器有这个名字的bean
   boolean containsBean(String name);
   //根据bean名字得到bean实例,并同时判断这个bean是不是单例
   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;
   //得到bean实例的Class类型
   @Nullable
   Class<?> getType(String name) throws NoSuchBeanDefinitionException;
   //得到bean的别名,如果根据别名检索,那么其原名也会被检索出来
   String[] getAliases(String name);

}

在BeanFactory 里只对 IOC 容器的基本行为作了定义,根本不关心你的 Bean 是如何定义怎样加载的。正如我们只关心工厂里得到什么的产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心。而要知道工厂是如何产生对象的,我们需要看具体的IOC 容器实现,Spring提供了许多IOC容器的实现 。 比如GenericApplicationContext , ClasspathXmlApplicationContext 等 。
ApplicationContext 是Spring提供的一个高级的IOC容器,也是继承了BeanFactory,它除了能够提供 IOC 容器的基本功能外,还为用户提供了以下的附加服务。从 ApplicationContext 接口的实现,我们看出其特点:

  1. 支持信息源,可以实现国际化。(实现 MessageSource 接口)
  2. 访问资源。(实现 ResourcePatternResolver 接口)
  3. 支持应用事件。(实现 ApplicationEventPublisher 接口)
  • BeanDefinition
    SpringIOC 容器管理了我们定义的各种 Bean 对象及其相互的关系,Bean 对象在 Spring 实现中是以 BeanDefinition 来描述的。 BeanDefinition 主要是用来描述 Bean,其存储了 Bean 的相关信息,Spring 实例化 Bean 时需读取该 Bean 对应的 BeanDefinition。BeanDefinition 整体可以分为两类,一类是描述通用的 Bean,还有一类是描述注解形式的 Bean。一般前者在 XML 时期定义 <bean‘> 标签以及在 Spring 内部使用较多,而现今我们大都使用后者,通过注解形式加载 Bean。
    其继承体系如下:
    在这里插入图片描述

  • BeanDefinitionReader
    Bean 的解析过程非常复杂,功能被分的很细,因为这里需要被扩展的地方很多,必须保证有足够的灵活性,以应对可能的变化。Bean 的解析主要就是对 Spring 配置文件的解析。这个解析过程主要通过BeanDefintionReader 来完成,最后看看 Spring 中 BeanDefintionReader 的类结构图:
    在这里插入图片描述
    通过BeanFactory,BeanDefinition,BeanDefinitionReader完成了IOC的初始化。

  1. Web IOC 容器
    从大家最熟悉的 DispatcherServlet 开始,我们最先想到的还是 DispatcherServlet 的 init()方法。在 DispatherServlet 中并没有找到 init()方法。往上追索在其父类HttpServletBean 中找到了我们想要的 init()方法,如下:
@Override
public final void init() throws ServletException {
   if (logger.isDebugEnabled()) {
      logger.debug("Initializing servlet '" + getServletName() + "'");
   }


   // Set bean properties from init parameters.
   PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
   if (!pvs.isEmpty()) {
      try {
         //定位资源
         BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
         //加载配置信息
         ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
         bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
         initBeanWrapper(bw);
         bw.setPropertyValues(pvs, true);
      }
      catch (BeansException ex) {
         if (logger.isErrorEnabled()) {
            logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
         }
         throw ex;
      }
   }


   // Let subclasses do whatever initialization they like.
   initServletBean();

   if (logger.isDebugEnabled()) {
      logger.debug("Servlet '" + getServletName() + "' configured successfully");
   }
}

在init()方法中,真正完成初始化容器动作的逻辑其实在 initServletBean()方法中,继续跟进initServletBean()中的代码在 FrameworkServlet 类中:

@Override
protected final void initServletBean() throws ServletException {
   getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
   if (this.logger.isInfoEnabled()) {
      this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
   }
   long startTime = System.currentTimeMillis();


   try {


      this.webApplicationContext = initWebApplicationContext();
      initFrameworkServlet();
   }
   catch (ServletException ex) {
      this.logger.error("Context initialization failed", ex);
      throw ex;
   }
   catch (RuntimeException ex) {
      this.logger.error("Context initialization failed", ex);
      throw ex;
   }


   if (this.logger.isInfoEnabled()) {
      long elapsedTime = System.currentTimeMillis() - startTime;
      this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
            elapsedTime + " ms");
   }
}

在上面的代码中终于看到了我们似曾相识的代码 initWebAppplicationContext(),继续跟进:

protected WebApplicationContext initWebApplicationContext() {


   //先从ServletContext中获得父容器WebApplicationContext
   WebApplicationContext rootContext =
         WebApplicationContextUtils.getWebApplicationContext(getServletContext());
   //声明子容器
   WebApplicationContext wac = null;


   //建立父、子容器之间的关联关系
   if (this.webApplicationContext != null) {
      // A context instance was injected at construction time -> use it
      wac = this.webApplicationContext;
      if (wac instanceof ConfigurableWebApplicationContext) {
         ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
         if (!cwac.isActive()) {
            // The context has not yet been refreshed -> provide services such as
            // setting the parent context, setting the application context id, etc
            if (cwac.getParent() == null) {
               // The context instance was injected without an explicit parent -> set
               // the root application context (if any; may be null) as the parent
               cwac.setParent(rootContext);
            }
            //这个方法里面调用了AbstractApplicationContext的refresh()方法
            //模板方法,规定IOC初始化基本流程
            configureAndRefreshWebApplicationContext(cwac);
         }
      }
   }
   //先去ServletContext中查找Web容器的引用是否存在,并创建好默认的空IOC容器
   if (wac == null) {
      // No context instance was injected at construction time -> see if one
      // has been registered in the servlet context. If one exists, it is assumed
      // that the parent context (if any) has already been set and that the
      // user has performed any initialization such as setting the context id
      wac = findWebApplicationContext();
   }
   //给上一步创建好的IOC容器赋值
   if (wac == null) {
      // No context instance is defined for this servlet -> create a local one
      wac = createWebApplicationContext(rootContext);
   }


   //触发onRefresh方法
   if (!this.refreshEventReceived) {
      // Either the context is not a ConfigurableApplicationContext with refresh
      // support or the context injected at construction time had already been
      // refreshed -> trigger initial onRefresh manually here.
      onRefresh(wac);
   }


   if (this.publishContext) {
      // Publish the context as a servlet context attribute.
      String attrName = getServletContextAttributeName();
      getServletContext().setAttribute(attrName, wac);
      if (this.logger.isDebugEnabled()) {
         this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
               "' as ServletContext attribute with name [" + attrName + "]");
      }
   }


   return wac;
}

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
   if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
      // The application context id is still set to its original default value
      // -> assign a more useful id based on available information
      if (this.contextId != null) {
         wac.setId(this.contextId);
      }
      else {
         // Generate default id...
         wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
               ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
      }
   }


   wac.setServletContext(getServletContext());
   wac.setServletConfig(getServletConfig());
   wac.setNamespace(getNamespace());
   wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));


   // The wac environment's #initPropertySources will be called in any case when the context
   // is refreshed; do it eagerly here to ensure servlet property sources are in place for
   // use in any post-processing or initialization that occurs below prior to #refresh
   ConfigurableEnvironment env = wac.getEnvironment();
   if (env instanceof ConfigurableWebEnvironment) {
      ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
   }


   postProcessWebApplicationContext(wac);
   applyInitializers(wac);
   wac.refresh();
}

从上面的代码中可以看出,在 configAndRefreshWebApplicationContext()方法中,调用AbstractApplicationContext的 refresh()方法,这个是真正启动 IOC 容器的入口。IOC 容器初始化以后,最后调用了DispatcherServlet 的 onRefresh()方法,在 onRefresh()方法中又是直接调用 initStrategies()方法初始化 SpringMVC 的九大组件

@Override
protected void onRefresh(ApplicationContext context) {
   initStrategies(context);
}


/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
//初始化策略
protected void initStrategies(ApplicationContext context) {
   //多文件上传的组件
   initMultipartResolver(context);
   //初始化本地语言环境
   initLocaleResolver(context);
   //初始化模板处理器
   initThemeResolver(context);
   //handlerMapping
   initHandlerMappings(context);
   //初始化参数适配器
   initHandlerAdapters(context);
   //初始化异常拦截器
   initHandlerExceptionResolvers(context);
   //初始化视图预处理器
   initRequestToViewNameTranslator(context);
   //初始化视图转换器
   initViewResolvers(context);
   //
   initFlashMapManager(context);
}

Spring IOC容器初始化三部曲
在这里插入图片描述
注意:加载这个过程中,会得到类是否为单例或者原型,只有单例模式的bean,在spring一启动的时候才会被初始化

基于XML的IOC容器初始化(定位、加载和注册)
在这里插入图片描述

基于Annotation 的IOC容器初始化(定位、加载和注册)
在这里插入图片描述

  1. IOC 容器初始化小结
    通过上面的代码,总结一下 IOC 容器初始化的基本步骤:
    1、初始化的入口在容器实现中的 refresh()调用来完成。
    2、对 Bean 定义载入 IOC 容器使用的方法是 loadBeanDefinition()。其中的大致过程如下:

通过 ResourceLoader 来完成资源文件位置的定位DefaultResourceLoader是默认的实现,同时上下文本身就给出了ResourceLoader的实现,可以从类路径,文件系统,URL 等方式来定为资源位置。如果是 XmlBeanFactory 作为 IOC 容器,那么需要为它指定 Bean 定义的资源,也就是说 Bean 定义文件 时通过抽象成 Resource 来被 IOC 容器处理的 , 容器通过BeanDefinitionReader 来完成定义信息的解析和 Bean 信息的注册, 往往使用的是
XmlBeanDefinitionReader 来解析 Bean 的 XML 定义文件 - 实际的处理过程是委托给BeanDefinitionParserDelegate 来完成的,从而得到 bean 的定义信息,这些信息在Spring 中使用BeanDefinition对象来表示-这个名字可以让我们想到loadBeanDefinition(),registerBeanDefinition()这些相关方法。它们都是为处理 BeanDefinitin 服务的,容器解析得到 BeanDefinition 以后,需要把它在 IOC 容器中注册,这由 IOC 实现 BeanDefinitionRegistry 接口来实现。注册过程就是在 IOC 容器内部维护的一个 HashMap 来保存得到的 BeanDefinition 的过程。这个 HashMap 是 IOC 容器持有Bean 信息的场所,以后对 Bean 的操作都是围绕这个HashMap 来实现的。然后我们就可以通过 BeanFactory 和 ApplicationContext 来享受到 Spring IOC 的服务了,在使用 IOC容器的时候,我们注意到除了少量粘合代码,绝大多数以正确 IOC 风格编写的应用程序代码完全不用关心如何到达工厂,因为容器将把这些对象与容器管理的其他对象钩在一起。基本的策略是把工厂放到已知的地方,最好是放在对预期使用的上下文有意义的地方,以及代码将实际需要访问工厂的地方。Spring本身提供了对声明式载入 web 应用程序用法的应用程序上下文,并将其存储在 ServletContext 中的框架实现。

以下是容器初始化全过程的时序图:

二、基于XML的IOC容器初始化

IOC 容器的初始化包括 BeanDefinition 的 Resource 定位、加载和注册这三个基本的过程。以ApplicationContext 为例演示,ApplicationContext 系列容器也许是我们最熟悉的,因为 Web 项目中使用的 XmlWebApplicationContext 就属于这个继承体系,还有 ClasspathXmlApplicationContext等,其继承体系如下图所示:
在这里插入图片描述

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

  1. 寻找入口

还有一个我们用的比较多的 ClassPathXmlApplicationContext,通过 main()方法启动:

ApplicationContext app = new ClassPathXmlApplicationContext("application.xml");

先看其构造函数的调用:

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

其实际调用的构造函数为:

public ClassPathXmlApplicationContext(
      String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
      throws BeansException {
      super(parent);
      setConfigLocations(configLocations);
       if (refresh) {
      refresh();
   }
}

还有像 AnnotationConfigApplicationContext 、 FileSystemXmlApplicationContext 、XmlWebApplicationContext 等都继承自父容器 AbstractApplicationContext主要用到了装饰器模式和策略模式,最终都是调用 refresh()方法。

  1. 获得配置路径

通过分析ClassPathXmlApplicationContext 的源代码可以知道 ,在创建ClassPathXmlApplicationContext 容器时,构造方法做以下两项重要工作:

  • 首先,调用父类容器的构造方法(super(parent)方法)为容器设置好Bean资源加载器。
  • 然后,再调用父类AbstractRefreshableConfigApplicationContext的setConfigLocations(configLocations)方法设置 Bean 配置信息的定位路径。
//解析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++) {
         // resolvePath为同一个类中将字符串解析为路径的方法
         this.configLocations[i] = resolvePath(locations[i]).trim();
      }
   }
   else {
      this.configLocations = null;
   }
}

通过追踪ClassPathXmlApplicationContext的继承体系 , 发现其父类的父类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.)
      //为了避免应用程序在Weblogic8.1关闭时出现类加载异常加载问题,加载IoC容
      //器关闭事件(ContextClosedEvent)类
      ContextClosedEvent.class.getName();
   }
    public AbstractApplicationContext() {
       this.resourcePatternResolver = getResourcePatternResolver();
    }
    public AbstractApplicationContext(@Nullable ApplicationContext parent) {
       this();
       setParent(parent);
    }
    //获取一个Spring Source的加载器用于读入Spring Bean定义资源文件
    protected ResourcePatternResolver getResourcePatternResolver() {
       //AbstractApplicationContext继承DefaultResourceLoader,因此也是一个资源加载器
       //Spring资源加载器,其getResource(String location)方法用于载入资源
       return new PathMatchingResourcePatternResolver(this);
    }
}

AbstractApplicationContext 的默认构造方法中有调用 PathMatchingResourcePatternResolver 的构造方法创建 Spring 资源加载器:

public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
   Assert.notNull(resourceLoader, "ResourceLoader must not be null");
   //设置Spring的资源加载器
   this.resourceLoader = resourceLoader;
}

在设置容器的资源加载器之后,接下来 ClassPathXmlApplicationContext 执行 setConfigLocations()方法通过调用其父类 AbstractRefreshableConfigApplicationContext 的方法进行对 Bean 配置信息的定位,该方法的源码如下:

//处理单个资源文件路径为一个字符串的情况
public void setConfigLocation(String location) {
   //String CONFIG_LOCATION_DELIMITERS = ",; /t/n";
   //即多个资源文件路径之间用” ,; \t\n”分隔,解析成数组形式
   setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));
}


/**
* Set the config locations for this application context.
* <p>If not set, the implementation may use a default as appropriate.
*/
//解析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++) {
         // resolvePath为同一个类中将字符串解析为路径的方法
         this.configLocations[i] = resolvePath(locations[i]).trim();
      }
   }
   else {
      this.configLocations = null;
   }
}

通过这两个方法的源码我们可以看出,我们既可以使用一个字符串来配置多个 Spring Bean 配置信息,也可以使用字符串数组,即下面两种方式都是可以的:

ClassPathXmlApplicationContext res = new ClassPathXmlApplicationContext("a.xml,b.xml");

多个资源文件路径之间可以是用” , ; \t\n”等分隔。

ClassPathXmlApplicationContext res =new ClassPathXmlApplicationContext(new String[]{"a.xml","b.xml"});

至此,SpringIOC 容器在初始化时将配置的 Bean 配置信息定位为 Spring 封装的 Resource。

  1. 开始启动

SpringIOC 容器对 Bean 配置资源的载入是从 refresh()函数开始的,refresh()是一个模板方法,规定了IOC容器的启动流程 , 有些逻辑要交给其子类去实现。它对Bean配置资源进行载入ClassPathXmlApplicationContext 通过调用其父类 AbstractApplicationContext 的 refresh()函数启动整个 IOC 容器对 Bean 定义的载入过程,现在我们来详细看看 refresh()中的逻辑处理:

@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      //1、调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识
      prepareRefresh();

      // Tell the subclass to refresh the internal bean factory.
      //2、告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从
      //子类的refreshBeanFactory()方法启动
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      //3、为BeanFactory配置容器特性,例如类加载器、事件处理器等
      prepareBeanFactory(beanFactory);

      try {
         // Allows post-processing of the bean factory in context subclasses.
         //4、为容器的某些子类指定特殊的BeanPost事件处理器
         postProcessBeanFactory(beanFactory);

         // Invoke factory processors registered as beans in the context.
         //5、调用所有注册的BeanFactoryPostProcessor的Bean
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         //6、为BeanFactory注册BeanPost事件处理器.
         //BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件
         registerBeanPostProcessors(beanFactory);

         // Initialize message source for this context.
         //7、初始化信息源,和国际化相关.
         initMessageSource();

         // Initialize event multicaster for this context.
         //8、初始化容器事件传播器.
         initApplicationEventMulticaster();

         // Initialize other special beans in specific context subclasses.
         //9、调用子类的某些特殊Bean初始化方法
         onRefresh();

         // Check for listener beans and register them.
         //10、为事件传播器注册事件监听器.
         registerListeners();

         // Instantiate all remaining (non-lazy-init) singletons.
         //11、初始化所有剩余的单例Bean
         finishBeanFactoryInitialization(beanFactory);

         // Last step: publish corresponding event.
         //12、初始化容器的生命周期事件处理器,并发布容器的生命周期事件
         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.
         //13、销毁已创建的Bean
         destroyBeans();

         // Reset 'active' flag.
         //14、取消refresh操作,重置容器的同步标识。
         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...
         //15、重设公共缓存
         resetCommonCaches();
      }
   }
}

refresh()方法主要为IOC容器Bean的生命周期管理提供条件,Spring IOC容器载入Bean配置信息从其子类容器的refreshBeanFactory()方法启动, 所以整个refresh()中“ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();”这句以后代码的都是注册容器的信息源和生命周期事件,我们前面说的载入就是从这句代码开始启动。
refresh()方法的主要作用是:在创建IOC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IOC容器。它类似于对IOC容器的重启,在新建立好的容器中对容器进行初始化,对Bean配置资源进行载入。

  1. 创建容器
    obtainFreshBeanFactory()方法调用子类容器的 refreshBeanFactory()方法,启动容器载入 Bean 配置信息的过程,代码如下:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   //这里使用了委派设计模式,父类定义了抽象的refreshBeanFactory()方法,具体实现调用子类容器的refreshBeanFactory()方法
   refreshBeanFactory();
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (logger.isDebugEnabled()) {
      logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
   }
   return beanFactory;
}

AbstractApplicationContext 类中只抽象定义了 refreshBeanFactory()方法, 容器真正调用的是其子类 AbstractRefreshableApplicationContext 实现的 refreshBeanFactory()方法,方法的源码如下:

@Override
protected final void refreshBeanFactory() throws BeansException {
   //如果已经有容器,销毁容器中的bean,关闭容器
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      //创建IOC容器
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      beanFactory.setSerializationId(getId());
      //对IOC容器进行定制化,如设置启动参数,开启注解的自动装配等
      customizeBeanFactory(beanFactory);
      //调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
         this.beanFactory = beanFactory;
      }
   }
   catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
   }
}

在这个方法中,先判断 BeanFactory 是否存在,如果存在则先销毁 beans 并关闭 beanFactory,接着创建 DefaultListableBeanFactory,并调用 loadBeanDefinitions(beanFactory)装载 bean 定义。

  1. 载入配置路径

AbstractRefreshableApplicationContext 中只定义了抽象的 loadBeanDefinitions 方法,容器真正调用的是其子类 AbstractXmlApplicationContext 对该方法的实现,AbstractXmlApplicationContext的主要源码如下:
loadBeanDefinitions()方法同样是抽象方法 , 是由其子类实现的,也即 在AbstractXmlApplicationContext 中。

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {

   //实现父类抽象的载入Bean定义方法
   @Override
   protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
      // Create a new XmlBeanDefinitionReader for the given BeanFactory.
      //创建XmlBeanDefinitionReader,即创建Bean读取器,并通过回调设置到容器中去,容  器使用该读取器读取Bean定义资源
      XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);


      // Configure the bean definition reader with this context's
      // resource loading environment.
      //为Bean读取器设置Spring资源加载器,AbstractXmlApplicationContext的
      //祖先父类AbstractApplicationContext继承DefaultResourceLoader,因此,容器本身也是一个资源加载器
      beanDefinitionReader.setEnvironment(this.getEnvironment());
      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.
      //当Bean读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制
      initBeanDefinitionReader(beanDefinitionReader);
      //Bean读取器真正实现加载的方法
      loadBeanDefinitions(beanDefinitionReader);
   }


 
   protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
      reader.setValidating(this.validating);
   }

   //Xml Bean读取器加载Bean定义资源
   protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
      //获取Bean定义资源的定位
      Resource[] configResources = getConfigResources();
      if (configResources != null) {
         //Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位
         //的Bean定义资源
         reader.loadBeanDefinitions(configResources);
      }
      //如果子类中获取的Bean定义资源定位为空,则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源
      String[] configLocations = getConfigLocations();
      if (configLocations != null) {
         //Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位
         //的Bean定义资源
         reader.loadBeanDefinitions(configLocations);
      }
   }

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

以XmlBean 读取器的其中一种策略 XmlBeanDefinitionReader 为例。XmlBeanDefinitionReader 调用其父类AbstractBeanDefinitionReader的 reader.loadBeanDefinitions()方法读取Bean配置资源。由于我们使用 ClassPathXmlApplicationContext 作为例子分析,因此 getConfigResources 的返回值为 null,因此程序执行 reader.loadBeanDefinitions(configLocations)分支。

  1. 分配路径处理策略

在 XmlBeanDefinitionReader 的抽象父类 AbstractBeanDefinitionReader 中定义了载入过程。
AbstractBeanDefinitionReader 的 loadBeanDefinitions()方法源码如下:

//重载方法,调用下面的loadBeanDefinitions(String, Set<Resource>);方法
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
   return loadBeanDefinitions(location, null);
}

public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
   //获取在IoC容器初始化过程中设置的资源加载器
   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 {
         //将指定位置的Bean定义资源文件解析为Spring IOC容器封装的资源
         //加载多个指定位置的Bean定义资源文件
         Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
         //委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
         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.
      //将指定位置的Bean定义资源文件解析为Spring IOC容器封装的资源
      //加载单个指定位置的Bean定义资源文件
      Resource resource = resourceLoader.getResource(location);
      //委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
      int loadCount = loadBeanDefinitions(resource);
      if (actualResources != null) {
         actualResources.add(resource);
      }
      if (logger.isDebugEnabled()) {
         logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
      }
      return loadCount;
   }
}


//重载方法,调用loadBeanDefinitions(String);
@Override
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;
}

AbstractRefreshableConfigApplicationContext 的 loadBeanDefinitions(Resource…resources) 方法实际上是调用 AbstractBeanDefinitionReader 的 loadBeanDefinitions()方法。从对 AbstractBeanDefinitionReader 的 loadBeanDefinitions()方法源码分析可以看出该方法就做了两件事:

  • 首先,调用资源加载器的获取资源方法
    resourceLoader.getResource(location),获取到要加载的资源。
  • 其次,真正执行加载功能是其子类XmlBeanDefinitionReader 的
    loadBeanDefinitions()方法。在loadBeanDefinitions()方法中调用了
    AbstractApplicationContext 的 getResources()方法,跟进去之后发现
    getResources()方法其实定义在 ResourcePatternResolver 中。

此时,我们有必要来看一下ResourcePatternResolver 的全类图:

在这里插入图片描述
在这里插入图片描述

从上面可以看到 ResourceLoader 与 ApplicationContext 的继承关系,可以看出其实际调用的是DefaultResourceLoader 中 的 getResource() 方 法 定 位 Resource ,因 为ClassPathXmlApplicationContext 本身就是 DefaultResourceLoader 的实现类,所以此时又回到了ClassPathXmlApplicationContext 中来。

  1. 解析配置文件路径

XmlBeanDefinitionReader通过调用ClassPathXmlApplicationContext的父类DefaultResourceLoader 的 getResource()方法获取要加载的资源,其源码如下:

//获取Resource的具体实现方法
@Override
public Resource getResource(String location) {
   Assert.notNull(location, "Location must not be null");
   for (ProtocolResolver protocolResolver : this.protocolResolvers) {
      Resource resource = protocolResolver.resolve(location, this);
      if (resource != null) {
         return resource;
      }
   }
   //如果是类路径的方式,那需要使用ClassPathResource 来得到bean 文件的资源对象
   if (location.startsWith("/")) {
      return getResourceByPath(location);
   }
   else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
      return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
   }
   else {
      try {
         // Try to parse the location as a URL...
         // 如果是URL 方式,使用UrlResource 作为bean 文件的资源对象
         URL url = new URL(location);
         return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
      }
      catch (MalformedURLException ex) {
         // No URL -> resolve as resource path.
         //如果既不是classpath标识,又不是URL标识的Resource定位,则调用
         //容器本身的getResourceByPath方法获取Resource
         return getResourceByPath(location);
      }
   }
}

DefaultResourceLoader 提供了 getResourceByPath()方法的实现,就是为了处理既不是 classpath标识,又不是 URL 标识的 Resource 定位这种情况。

protected Resource getResourceByPath(String path) {
   return new ClassPathContextResource(path, getClassLoader());
}

在ClassPathResource 中完成了对整个路径的解析。这样,就可以从类路径上对 IOC 配置文件进行加载,当然我们可以按照这个逻辑从任何地方加载,在 Spring 中我们看到它提供的各种资源抽象,比如ClassPathResource、URLResource、FileSystemResource 等来供我们使用。上面我们看到的是定位 Resource 的一个过程,而这只是加载过程的一部分。例如 FileSystemXmlApplicationContext 容器就重写了getResourceByPath()方法:

@Override
protected Resource getResourceByPath(String path) {
   if (path.startsWith("/")) {
      path = path.substring(1);
   }
   //这里使用文件系统资源对象来定义bean 文件
   return new FileSystemResource(path);
}

通过子类的覆盖,巧妙地完成了将类路径变为文件路径的转换。

  1. 开始读取配置内容

继续回到 XmlBeanDefinitionReader 的 loadBeanDefinitions(Resource …)方法看到代表 bean 文件的资源定义以后的载入过程:

//从特定XML文件中实际载入Bean定义资源的方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
      throws BeanDefinitionStoreException {
   try {
      //将XML文件转换为DOM对象,解析过程由documentLoader实现
      Document doc = doLoadDocument(inputSource, resource);
      //这里是启动对Bean定义解析的详细过程,该解析过程会用到Spring的Bean配置规则
      return registerBeanDefinitions(doc, resource);
   }
}

通过源码分析,载入 Bean 配置信息的最后一步是将 Bean 配置信息转换为 Document 对象,该过程由documentLoader()方法实现。

  1. 准备文档对象

DocumentLoader 将 Bean 配置资源转换成 Document 对象的源码如下:

//使用标准的JAXP将载入的Bean定义资源转换成document对象
@Override
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;
         }
      }
   }
   return factory;
}

上面的解析过程是调用 JavaEE 标准的 JAXP 标准进行处理。 至此 Spring IOC 容器根据定位的 Bean 配置信息, 将其加载读入并转换成为 Document 对象过程完成。 接下来我们要继续分析 Spring IOC 容器将载入的 Bean 配置信息转换为 Document 对象之后, 是如何将其解析为 Spring IOC 管理的 Bean 对象并将其注册到容器中的。

  1. 分配解析策略

XmlBeanDefinitionReader 类中的 doLoadBeanDefinition()方法是从特定 XML 文件中实际载入Bean 配置资源的方法, 该方法在载入 Bean 配置资源之后将其转换为 Document 对象, 接下来调用registerBeanDefinitions() 启 动 Spring IOC 容 器 对 Bean 定 义 的 解 析 过 程 ,registerBeanDefinitions()方法源码如下:

//按照Spring的Bean语义要求将Bean定义资源解析并转换为容器内部数据结构
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
   //得到BeanDefinitionDocumentReader来对xml格式的BeanDefinition解析
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
   //获得容器中注册的Bean数量
   int countBefore = getRegistry().getBeanDefinitionCount();
   //解析过程入口,这里使用了委派模式,BeanDefinitionDocumentReader只是个接口,
   //具体的解析实现过程有实现类DefaultBeanDefinitionDocumentReader完成
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   //统计解析的Bean数量
   return getRegistry().getBeanDefinitionCount() - countBefore;
}

Bean 配置资源的载入解析分为以下两个过程:首先,通过调用 XML 解析器将 Bean 配置信息转换得到 Document 对象,但是这些 Document 对象并没有按照 Spring 的 Bean 规则进行解析。这一步是载入的过程其次,在完成通用的 XML 解析之后,按照 Spring Bean 的定义规则对 Document 对象进行解析,其解析过程是在接口 BeanDefinitionDocumentReader 的实现类DefaultBeanDefinitionDocumentReader 中实现。

  1. 将配置载入内存

BeanDefinitionDocumentReader 接 口 通 过 registerBeanDefinitions() 方法调用其实现类DefaultBeanDefinitionDocumentReader 对 Document 对象进行解析,解析的代码如下:

//根据Spring DTD对Bean的定义规则解析Bean定义Document对象
@Override
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实现,
   //BeanDefinitionParserDelegate中定义了Spring Bean定义XML文件的各种元素
   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;
}


//创建BeanDefinitionParserDelegate,用于完成真正的解析过程
protected BeanDefinitionParserDelegate createDelegate(
      XmlReaderContext readerContext, Element root, @Nullable BeanDefinitionParserDelegate parentDelegate) {


   BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
   //BeanDefinitionParserDelegate初始化Document根元素
   delegate.initDefaults(root, parentDelegate);
   return delegate;
}


/**
* Parse the elements at the root level in the document:
* "import", "alias", "bean".
* @param root the DOM root element of the document
*/
//使用Spring的Bean规则从Document的根元素开始进行Bean定义的Document对象
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
   //Bean定义的Document对象使用了Spring默认的XML命名空间
   if (delegate.isDefaultNamespace(root)) {
      //获取Bean定义的Document对象根元素的所有子节点
      NodeList nl = root.getChildNodes();
      for (int i = 0; i < nl.getLength(); i++) {
         Node node = nl.item(i);
         //获得Document节点是XML元素节点
         if (node instanceof Element) {
            Element ele = (Element) node;
            //Bean定义的Document的元素节点使用的是Spring默认的XML命名空间
            if (delegate.isDefaultNamespace(ele)) {
               //使用Spring的Bean规则解析元素节点
               parseDefaultElement(ele, delegate);
            }
            else {
               //没有使用Spring默认的XML命名空间,则使用用户自定义的解//析规则解析元素节点
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      //Document的根节点没有使用Spring默认的命名空间,则使用用户自定义的
      //解析规则解析Document根节点
      delegate.parseCustomElement(root);
   }
}




//使用Spring的Bean规则解析Document元素节点
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
   //如果元素节点是<Import>导入元素,进行导入解析
   if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
      importBeanDefinitionResource(ele);
   }
   //如果元素节点是<Alias>别名元素,进行别名解析
   else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
      processAliasRegistration(ele);
   }
   //元素节点既不是导入元素,也不是别名元素,即普通的<Bean>元素,
   //按照Spring的Bean规则解析元素
   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.
*/
//解析<Import>导入元素,从给定的导入路径加载Bean定义资源到Spring IoC容器中
protected void importBeanDefinitionResource(Element ele) {
   //获取给定的导入元素的location属性
   String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
   //如果导入元素的location属性值为空,则没有导入任何资源,直接返回
   if (!StringUtils.hasText(location)) {
      getReaderContext().error("Resource location must not be empty", ele);
      return;
   }


   // Resolve system properties: e.g. "${user.dir}"
   //使用系统变量值解析location属性值
   location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);


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


   // Discover whether the location is an absolute or relative URI
   //标识给定的导入元素的location是否是绝对路径
   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*:"
      //给定的导入元素的location不是绝对路径
   }


   // Absolute or relative?
   //给定的导入元素的location是绝对路径
   if (absoluteLocation) {
      try {
         //使用资源读入器加载给定路径的Bean定义资源
         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.
      //给定的导入元素的location是相对路径
      try {
         int importCount;
         //将给定导入元素的location封装为相对路径资源
         Resource relativeResource = getReaderContext().getResource().createRelative(location);
         //封装的相对路径资源存在
         if (relativeResource.exists()) {
            //使用资源读入器加载Bean定义资源
            importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
            actualResources.add(relativeResource);
         }
         //封装的相对路径资源不存在
         else {
            //获取Spring IOC容器资源读入器的基本路径
            String baseLocation = getReaderContext().getResource().getURL().toString();
            //根据Spring IOC容器资源读入器的基本路径加载给定导入路径的资源
            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()]);
   //在解析完<Import>元素之后,发送容器导入其他资源处理完成事件
   getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}


/**
* Process the given alias element, registering the alias with the registry.
*/
//解析<Alias>别名元素,为Bean向Spring IoC容器注册别名
protected void processAliasRegistration(Element ele) {
   //获取<Alias>别名元素中name的属性值
   String name = ele.getAttribute(NAME_ATTRIBUTE);
   //获取<Alias>别名元素中alias的属性值
   String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
   boolean valid = true;
   //<alias>别名元素的name属性值为空
   if (!StringUtils.hasText(name)) {
      getReaderContext().error("Name must not be empty", ele);
      valid = false;
   }
   //<alias>别名元素的alias属性值为空
   if (!StringUtils.hasText(alias)) {
      getReaderContext().error("Alias must not be empty", ele);
      valid = false;
   }
   if (valid) {
      try {
         //向容器的资源读入器注册别名
         getReaderContext().getRegistry().registerAlias(name, alias);
      }
      catch (Exception ex) {
         getReaderContext().error("Failed to register alias '" + alias +
               "' for bean with name '" + name + "'", ele, ex);
      }
      //在解析完<Alias>元素之后,发送容器别名处理完成事件
      getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
   }
}


/**
* Process the given bean element, parsing the bean definition
* and registering it with the registry.
*/
//解析Bean定义资源Document对象的普通元素
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   // BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类
   //对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现
   // BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // Register the final decorated instance.
         //向Spring IOC容器注册解析得到的Bean定义,这是Bean定义向IOC容器注册的入口
         BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      catch (BeanDefinitionStoreException ex) {
         getReaderContext().error("Failed to register bean definition with name '" +
               bdHolder.getBeanName() + "'", ele, ex);
      }
      // Send registration event.
      //在完成向Spring IOC容器注册解析得到的Bean定义之后,发送注册事件
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}

通过上述 Spring IOC 容器对载入的 Bean 定义 Document 解析可以看出,我们使用 Spring 时,在Spring 配置文件中可以使用元素来导入 IOC 容器所需要的其他资源,Spring IOC 容器在解析时会首先将指定导入的资源加载进容器中。使用别名时,Spring IOC 容器首先将别名元素所定义的别名注册到容器中。
对于既不是元素,又不是元素的元素,即 Spring 配置文件中普通的元素的解析由 BeanDefinitionParserDelegate 类的 parseBeanDefinitionElement()方法来实现。这个解析的过程非常复杂。

  1. 载入元素
    Bean 配置信息中的和元素解析在 DefaultBeanDefinitionDocumentReader 中已经完成,对 Bean 配置信息中使用最多的元素交由 BeanDefinitionParserDelegate 来解析,其解析实现的源码如下:
//解析<Bean>元素的入口
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
   return parseBeanDefinitionElement(ele, null);
}


/**
* Parses the supplied {@code <bean>} element. May return {@code null}
* if there were errors during parse. Errors are reported to the
* {@link org.springframework.beans.factory.parsing.ProblemReporter}.
*/
//解析Bean定义资源文件中的<Bean>元素,这个方法中主要处理<Bean>元素的id,name和别名属性
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
   //获取<Bean>元素中的id属性值
   String id = ele.getAttribute(ID_ATTRIBUTE);
   //获取<Bean>元素中的name属性值
   String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);


   //获取<Bean>元素中的alias属性值
   List<String> aliases = new ArrayList<>();


   //将<Bean>元素中的所有name属性值存放到别名中
   if (StringUtils.hasLength(nameAttr)) {
      String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
      aliases.addAll(Arrays.asList(nameArr));
   }


   String beanName = id;
   //如果<Bean>元素中没有配置id属性时,将别名中的第一个值赋值给beanName
   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");
      }
   }


   //检查<Bean>元素所配置的id或者name的唯一性,containingBean标识<Bean>
   //元素中是否包含子<Bean>元素
   if (containingBean == null) {
      //检查<Bean>元素所配置的id、name或者别名是否重复
      checkNameUniqueness(beanName, aliases, ele);
   }


   //详细对<Bean>元素中配置的Bean定义进行解析的地方
   AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
   if (beanDefinition != null) {
      if (!StringUtils.hasText(beanName)) {
         try {
            if (containingBean != null) {
               //如果<Bean>元素中没有配置id、别名或者name,且没有包含子元素
               //<Bean>元素,为解析的Bean生成一个唯一beanName并注册
               beanName = BeanDefinitionReaderUtils.generateBeanName(
                     beanDefinition, this.readerContext.getRegistry(), true);
            }
            else {
               //如果<Bean>元素中没有配置id、别名或者name,且包含了子元素
               //<Bean>元素,为解析的Bean使用别名向IOC容器注册
               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.
               //为解析的Bean使用别名注册时,为了向后兼容
               //Spring1.2/2.0,给别名添加类名后缀
               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);
   }
   //当解析出错时,返回null
   return null;
}


/**
* Validate that the specified bean name and aliases have not been used already
* within the current level of beans element nesting.
*/
protected void checkNameUniqueness(String beanName, List<String> aliases, Element beanElement) {
   String foundName = null;


   if (StringUtils.hasText(beanName) && this.usedNames.contains(beanName)) {
      foundName = beanName;
   }
   if (foundName == null) {
      foundName = CollectionUtils.findFirstMatch(this.usedNames, aliases);
   }
   if (foundName != null) {
      error("Bean name '" + foundName + "' is already used in this <beans> element", beanElement);
   }


   this.usedNames.add(beanName);
   this.usedNames.addAll(aliases);
}


/**
* Parse the bean definition itself, without regard to name or aliases. May return
* {@code null} if problems occurred during the parsing of the bean definition.
*/
//详细对<Bean>元素中配置的Bean定义其他属性进行解析
//由于上面的方法中已经对Bean的id、name和别名等属性进行了处理
//该方法中主要处理除这三个以外的其他属性数据
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
      Element ele, String beanName, @Nullable BeanDefinition containingBean) {
   //记录解析的<Bean>
   this.parseState.push(new BeanEntry(beanName));


   //这里只读取<Bean>元素中配置的class名字,然后载入到BeanDefinition中去
   //只是记录配置的class名字,不做实例化,对象的实例化在依赖注入时完成
   String className = null;


   //如果<Bean>元素中配置了parent属性,则获取parent属性的值
   if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
      className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
   }
   String parent = null;
   if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
      parent = ele.getAttribute(PARENT_ATTRIBUTE);
   }


   try {
      //根据<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();
   }


   //解析<Bean>元素出错时,返回null
   return null;
}

只要使用过 Spring,对 Spring 配置文件比较熟悉的人,通过对上述源码的分析,就会明白我们在 Spring配置文件中元素的中配置的属性就是通过该方法解析和设置到 Bean 中去的。
注意:在解析<Bean>元素过程中没有创建和实例化 Bean 对象,只是创建了 Bean 对象的定义类BeanDefinition,将元素中的配置信息设置到 BeanDefinition 中作为记录,当依赖注入时才使用这些记录信息创建和实例化具体的 Bean 对象。
上面方法中一些对一些配置如元信息(meta)、qualifier 等的解析,我们在 Spring 中配置时使用的也不多,我们在使用 Spring 的元素时,配置最多的是属性,因此我们下面继续分析源码,了解 Bean 的属性在解析时是如何设置的。

  1. 载入元素
    BeanDefinitionParserDelegate 在解析调用 parsePropertyElements()方法解析元素中的属性子元素,解析源码如下:
//解析<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值
@Nullable
public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
   String elementName = (propertyName != null) ?
               "<property> element for property '" + propertyName + "'" :
               "<constructor-arg> element";


   // Should only have one child element: ref, value, list, etc.
   //获取<property>的所有子元素,只能是其中一种类型:ref,value,list,etc等
   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)) {
         // Child element is what we're looking for.
         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 {
      // Neither child element nor "ref" or "value" attribute found.
      //propery属性中既不是ref,也不是value属性,解析出错返回null
      error(elementName + " must specify a ref or value", ele);
      return null;
   }
}

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

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

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

  1. 载入的子元素
    在 BeanDefinitionParserDelegate 类中的 parsePropertySubElement()方法对中的子元素解析,源码如下:
//解析<property>元素中ref,value或者集合等子元素
@Nullable
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable 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)) {
      // A generic reference to any name of any bean.
      //可以不再同一个Spring配置文件中,具体请参考Spring对ref的配置规则
      String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
      boolean toParent = false;
      if (!StringUtils.hasLength(refName)) {
         // A reference to the id of another bean in a parent context.
         //获取<property>元素中parent属性值,引用父级容器中的Bean
         refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
         toParent = true;
         if (!StringUtils.hasLength(refName)) {
            error("'bean' or 'parent' is required for <ref> element", ele);
            return null;
         }
      }
      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)) {
      // It's a distinguished null value. Let's wrap it in a TypedStringValue
      // object in order to preserve the source location.
      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>元素中配置的 array、list、set、map、prop 等各种集合子元素的都通过上述方法解析,生成对应的数据对象,比如 ManagedList、ManagedArray、ManagedSet 等,这些 Managed 类是 Spring 对象 BeanDefiniton 的数据封装,对集合数据类型的具体解析有各自的解析方法实现,解析方法的命名非常规范,一目了然,我们对集合元素的解析方法进行源码分析,了解其实现过程。

  1. 载入的子元素

在 BeanDefinitionParserDelegate 类中的 parseListElement()方法就是具体实现解析<property>元素中的<list>集合子元素,源码如下:

/**
* Parse a list element.
*/
//解析<list>集合子元素
public List<Object> parseListElement(Element collectionEle, @Nullable 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<>(nl.getLength());
   target.setSource(extractSource(collectionEle));
   //设置集合目标数据类型
   target.setElementTypeName(defaultElementType);
   target.setMergeEnabled(parseMergeAttribute(collectionEle));
   //具体的<list>元素解析
   parseCollectionElements(nl, target, bd, defaultElementType);
   return target;
}


/**
* Parse a set element.
*/
public Set<Object> parseSetElement(Element collectionEle, @Nullable BeanDefinition bd) {
   String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
   NodeList nl = collectionEle.getChildNodes();
   ManagedSet<Object> target = new ManagedSet<>(nl.getLength());
   target.setSource(extractSource(collectionEle));
   target.setElementTypeName(defaultElementType);
   target.setMergeEnabled(parseMergeAttribute(collectionEle));
   parseCollectionElements(nl, target, bd, defaultElementType);
   return target;
}

//具体解析<list>集合元素,<array>、<list>和<set>都使用该方法解析
protected void parseCollectionElements(
      NodeList elementNodes, Collection<Object> target, @Nullable 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 容器的初始化过程(注意,只是初始化,还没依赖注入)。

  1. 分配注册策略

让我们继续跟踪程序的执行顺序,接下来我们来分析 DefaultBeanDefinitionDocumentReader 对Bean 定 义转 换的 Document 对 象解 析的 流程 中, 在其 parseDefaultElement() 方 法中 完成对Document对象的解析后得到封装 BeanDefinition 的 BeanDefinitionHold 对 象 , 然后调用 BeanDefinitionReaderUtils 的 registerBeanDefinition() 方法向IOC容器注册解析的 Bean ,BeanDefinitionReaderUtils 的注册的源码如下:

//将解析的BeanDefinitionHold注册到容器中
public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {


   // Register bean definition under primary name.
   //获取解析的BeanDefinition的名称
   String beanName = definitionHolder.getBeanName();
   //向IOC容器注册BeanDefinition
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());


   // Register aliases for bean name, if any.
   //如果解析的BeanDefinition有别名,向容器为其注册别名
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String alias : aliases) {
         registry.registerAlias(beanName, alias);
      }
   }
}

调用 BeanDefinitionReaderUtils 向 IOC 容器注册解析的 BeanDefinition 时,真正完成注册功能的是 DefaultListableBeanFactory。

  1. 向容器注册

DefaultListableBeanFactory 中使用一个HashMap的集合对象存放 IOC 容器中注册解析的BeanDefinition,向 IOC 容器注册的主要源码如下:
在这里插入图片描述

//存储注册信息的 BeanDefinition
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

//向IOC容器注册解析的BeanDefinition
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {


   Assert.hasText(beanName, "Bean name must not be empty");
   Assert.notNull(beanDefinition, "BeanDefinition must not be null");


   //校验解析的BeanDefiniton
   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<>(this.beanDefinitionNames.size() + 1);
            updatedDefinitions.addAll(this.beanDefinitionNames);
            updatedDefinitions.add(beanName);
            this.beanDefinitionNames = updatedDefinitions;
            if (this.manualSingletonNames.contains(beanName)) {
               Set<String> updatedSingletons = new LinkedHashSet<>(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;
   }


   //检查是否有同名的BeanDefinition已经在IOC容器中注册
   if (oldBeanDefinition != null || containsSingleton(beanName)) {
      //重置所有已经注册过的BeanDefinition的缓存
      resetBeanDefinition(beanName);
   }
}

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

时序图:
在这里插入图片描述

三、基于Annotation的IOC容器初始化

  1. Annotation 的前世今生

从 Spring2.0 以后的版本中,Spring 也引入了基于注解(Annotation)方式的配置,注解(Annotation)是 JDK1.5 中引入的一个新特性,用于简化 Bean 的配置,可以取代 XML 配置文件。开发人员对注解(Annotation)的态度也是萝卜青菜各有所爱,个人认为注解可以大大简化配置,提高开发速度,但也给后期维护增加了难度。目前来说 XML 方式发展的相对成熟,方便于统一管理。随着 Spring Boot 的兴 起,基于注解的开发甚至实现了零配置。但作为个人的习惯而言,还是倾向于 XML 配置文件和注解(Annotation)相互配合使用。Spring IOC 容器对于类级别的注解和类内部的注解分以下两种处理策略:

  1. 初始化过程
    在这里插入图片描述
  • 定位 Bean 扫描路径

在 Spring 中管理注解 Bean 定义的容器有两个 : AnnotationConfigApplicationContext 和AnnotationConfigWebApplicationContex。这两个类是专门处理 Spring 注解方式配置的容器,直接依赖于注解作为容器配置信息来源的 IOC 容器。AnnotationConfigWebApplicationContext 是AnnotationConfigApplicationContext 的 Web 版本,两者的用法以及对注解的处理方式几乎没有差别。现在我们以 AnnotationConfigApplicationContext 为例看看它的源码:

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {

   //保存一个读取注解的Bean定义读取器,并将其设置到容器中
   private final AnnotatedBeanDefinitionReader reader;

   //保存一个扫描指定类路径中注解Bean定义的扫描器,并将其设置到容器中
   private final ClassPathBeanDefinitionScanner scanner;

   //默认构造函数,初始化一个空容器,容器不包含任何 Bean 信息,需要在稍后通过调用其register()
   //方法注册配置类,并调用refresh()方法刷新容器,触发容器对注解Bean的载入、解析和注册过程
   public AnnotationConfigApplicationContext() {
      this.reader = new AnnotatedBeanDefinitionReader(this);
      this.scanner = new ClassPathBeanDefinitionScanner(this);
   }

   //最常用的构造函数,通过将涉及到的配置类传递给该构造函数,以实现将相应配置类中的Bean自动注册到容器中
   public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
      this();
      register(annotatedClasses);
      refresh();
   }

   //该构造函数会自动扫描以给定的包及其子包下的所有类,并自动识别所有的Spring Bean,将其注册到容器中
   public AnnotationConfigApplicationContext(String... basePackages) {
      this();
      scan(basePackages);
      refresh();
   }
   //为容器的注解Bean读取器和注解Bean扫描器设置Bean名称产生器
   public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
      this.reader.setBeanNameGenerator(beanNameGenerator);
      this.scanner.setBeanNameGenerator(beanNameGenerator);
      getBeanFactory().registerSingleton(
            AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
   }
   //为容器的注解Bean读取器和注解Bean扫描器设置作用范围元信息解析器
   public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
      this.reader.setScopeMetadataResolver(scopeMetadataResolver);
      this.scanner.setScopeMetadataResolver(scopeMetadataResolver);
   }
   
   //为容器注册一个要被处理的注解Bean,新注册的Bean,必须手动调用容器的
   //refresh()方法刷新容器,触发容器对新注册的Bean的处理
   public void register(Class<?>... annotatedClasses) {
      Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
      this.reader.register(annotatedClasses);
   }

   //扫描指定包路径及其子包下的注解类,为了使新添加的类被处理,必须手动调用
   //refresh()方法刷新容器
   public void scan(String... basePackages) {
      Assert.notEmpty(basePackages, "At least one base package must be specified");
      this.scanner.scan(basePackages);
   }

通过上面的源码分析,我们可以看啊到 Spring 对注解的处理分为两种方式:

  • 直接将注解 Bean
    注册到容器中可以在初始化容器时注册;也可以在容器创建之后手动调用注册方法向容器注册,然后通过手动刷新容器,使得容器对注册的注解 Bean
    进行处理。

  • 通过扫描指定的包及其子包下的所有类在初始化注解容器时指定要自动扫描的路径,如果容器创建以后向给定路径动态添加了注Bean,则需要手动调用容器扫描的方法,然后手动刷新容器,使得容器对所注册的 Bean进行处理。接下来,将会对两种处理方式详细分析其实现过程。

  • 读取 Annotation 元数据
    当创建注解处理容器时,如果传入的初始参数是具体的注解 Bean 定义类时,注解容器读取并注册。

1)、AnnotationConfigApplicationContext 通过调用注解 Bean 定义读取器
AnnotatedBeanDefinitionReader 的 register()方法向容器注册指定的注解 Bean,注解 Bean 定义读取器向容器注册注解 Bean 的源码如下:

//注册多个注解Bean定义类
public void register(Class<?>... annotatedClasses) {
   for (Class<?> annotatedClass : annotatedClasses) {
      registerBean(annotatedClass);
   }
}

//注册一个注解Bean定义类
public void registerBean(Class<?> annotatedClass) {
   doRegisterBean(annotatedClass, null, null, null);
}

//Bean定义读取器注册注解Bean定义的入口方法
@SuppressWarnings("unchecked")
public void registerBean(Class<?> annotatedClass, Class<? extends Annotation>... qualifiers) {
   doRegisterBean(annotatedClass, null, null, qualifiers);
}

//Bean定义读取器向容器注册注解Bean定义类
@SuppressWarnings("unchecked")
public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
   doRegisterBean(annotatedClass, null, name, qualifiers);
}

//Bean定义读取器向容器注册注解Bean定义类
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
      @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {


   //根据指定的注解Bean定义类,创建Spring容器中对注解Bean的封装的数据结构
   AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
   if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
      return;
   }


   abd.setInstanceSupplier(instanceSupplier);
   //解析注解Bean定义的作用域,若@Scope("prototype"),则Bean为原型类型;
   //若@Scope("singleton"),则Bean为单态类型
   ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
   //为注解Bean定义设置作用域
   abd.setScope(scopeMetadata.getScopeName());
   //为注解Bean定义生成Bean名称
   String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));


   //处理注解Bean定义中的通用注解
   AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
   //如果在向容器注册注解Bean定义时,使用了额外的限定符注解,则解析限定符注解。
   //主要是配置的关于autowiring自动依赖注入装配的限定条件,即@Qualifier注解
   //Spring自动依赖注入装配默认是按类型装配,如果使用@Qualifier则按名称
   if (qualifiers != null) {
      for (Class<? extends Annotation> qualifier : qualifiers) {
         //如果配置了@Primary注解,设置该Bean为autowiring自动依赖注入装//配时的首选
         if (Primary.class == qualifier) {
            abd.setPrimary(true);
         }
         //如果配置了@Lazy注解,则设置该Bean为非延迟初始化,如果没有配置,
         //则该Bean为预实例化
         else if (Lazy.class == qualifier) {
            abd.setLazyInit(true);
         }
         //如果使用了除@Primary和@Lazy以外的其他注解,则为该Bean添加一
         //个autowiring自动依赖注入装配限定符,该Bean在进autowiring
         //自动依赖注入装配时,根据名称装配限定符指定的Bean
         else {
            abd.addQualifier(new AutowireCandidateQualifier(qualifier));
         }
      }
   }
   for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
      customizer.customize(abd);
   }


   //创建一个指定Bean名称的Bean定义对象,封装注解Bean定义类数据
   BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
   //根据注解Bean定义类中配置的作用域,创建相应的代理对象
   definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
   //向IOC容器注册注解Bean类定义对象
   BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

从上面的源码我们可以看出,注册注解 Bean 定义类的基本步骤:

  1. 需要使用注解元数据解析器解析注解 Bean 中关于作用域的配置。
  2. 使用 AnnotationConfigUtils 的processCommonDefinitionAnnotations()方法处理注解 Bean 定义类中通用的注解
  3. 使用AnnotationConfigUtils 的 applyScopedProxyMode()方法创建对于作用域的代理对象。
  4. 通过BeanDefinitionReaderUtils 向容器注册 Bean。

下面我们继续分析这 4 步的具体实现过程

2)、AnnotationScopeMetadataResolver 解析作用域元数据
AnnotationScopeMetadataResolver 通过 resolveScopeMetadata()方法解析注解 Bean 定义类的作用域元信息,即判断注册的 Bean 是原生类型(prototype)还是单态(singleton)类型,其源码如下:

//解析注解Bean定义类中的作用域元信息
@Override
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
   ScopeMetadata metadata = new ScopeMetadata();
   if (definition instanceof AnnotatedBeanDefinition) {
      AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
      //从注解Bean定义类的属性中查找属性为”Scope”的值,即@Scope注解的值
      //annDef.getMetadata().getAnnotationAttributes()方法将Bean
      //中所有的注解和注解的值存放在一个map集合中
      AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
            annDef.getMetadata(), this.scopeAnnotationType);
      //将获取到的@Scope注解的值设置到要返回的对象中
      if (attributes != null) {
         metadata.setScopeName(attributes.getString("value"));
         //获取@Scope注解中的proxyMode属性值,在创建代理对象时会用到
         ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
         //如果@Scope的proxyMode属性为DEFAULT或者NO
         if (proxyMode == ScopedProxyMode.DEFAULT) {
            //设置proxyMode为NO
            proxyMode = this.defaultProxyMode;
         }
         //为返回的元数据设置proxyMode
         metadata.setScopedProxyMode(proxyMode);
      }
   }
   //返回解析的作用域元信息对象
   return metadata;
}

3)、AnnotationConfigUtils 处理注解 Bean 定义类中的通用注解
AnnotationConfigUtils 类的 processCommonDefinitionAnnotations()在向容器注册 Bean 之前,首先对注解 Bean 定义类中的通用 Spring 注解进行处理,源码如下:

public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
   processCommonDefinitionAnnotations(abd, abd.getMetadata());
}


//处理Bean定义中通用注解
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
   AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
   //如果Bean定义中有@Lazy注解,则将该Bean预实例化属性设置为@lazy注解的值
   if (lazy != null) {
      abd.setLazyInit(lazy.getBoolean("value"));
   }


   else if (abd.getMetadata() != metadata) {
      lazy = attributesFor(abd.getMetadata(), Lazy.class);
      if (lazy != null) {
         abd.setLazyInit(lazy.getBoolean("value"));
      }
   }
   //如果Bean定义中有@Primary注解,则为该Bean设置为autowiring自动依赖注入装配的首选对象
   if (metadata.isAnnotated(Primary.class.getName())) {
      abd.setPrimary(true);
   }
   //如果Bean定义中有@ DependsOn注解,则为该Bean设置所依赖的Bean名称,
   //容器将确保在实例化该Bean之前首先实例化所依赖的Bean
   AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
   if (dependsOn != null) {
      abd.setDependsOn(dependsOn.getStringArray("value"));
   }


   if (abd instanceof AbstractBeanDefinition) {
      AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;
      AnnotationAttributes role = attributesFor(metadata, Role.class);
      if (role != null) {
         absBd.setRole(role.getNumber("value").intValue());
      }
      AnnotationAttributes description = attributesFor(metadata, Description.class);
      if (description != null) {
         absBd.setDescription(description.getString("value"));
      }
   }
}

4)、AnnotationConfigUtils 根据注解 Bean 定义类中配置的作用域为其应用相应的代理策略AnnotationConfigUtils 类的 applyScopedProxyMode()方法根据注解 Bean 定义类中配置的作用域@Scope 注解的值,为 Bean 定义应用相应的代理模式,主要是在 Spring 面向切面编程(AOP)中使用。源码如下:

//根据作用域为Bean应用引用的代码模式
static BeanDefinitionHolder applyScopedProxyMode(
      ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {


   //获取注解Bean定义类中@Scope注解的proxyMode属性值
   ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
   //如果配置的@Scope注解的proxyMode属性值为NO,则不应用代理模式
   if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
      return definition;
   }
   //获取配置的@Scope注解的proxyMode属性值,如果为TARGET_CLASS
   //则返回true,如果为INTERFACES,则返回false
   boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
   //为注册的Bean创建相应模式的代理对象
   return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}

这段为 Bean 引用创建相应模式的代理,这里不做深入的分析。

5)、BeanDefinitionReaderUtils 向容器注册 Bean
BeanDefinitionReaderUtils 主要是校验 BeanDefinition 信息,然后将 Bean 添加到容器中一个管理BeanDefinition 的 HashMap 中。

  • 扫描指定包并解析为 BeanDefinition
    当创建注解处理容器时,如果传入的初始参数是注解 Bean 定义类所在的包时,注解容器将扫描给定的包及其子包,将扫描到的注解 Bean 定义载入并注册。

1)、ClassPathBeanDefinitionScanner 扫描给定的包及其子包
AnnotationConfigApplicationContext 通过调用scan()方法调用类路径 Bean 定义扫描器ClassPathBeanDefinitionScanner 扫描给定包及其子包下的所有类,主要源码如下:

//调用类路径Bean定义扫描器入口方法
public int scan(String... basePackages) {
   //获取容器中已经注册的Bean个数
   int beanCountAtScanStart = this.registry.getBeanDefinitionCount();


   //启动扫描器扫描给定包
   doScan(basePackages);


   // Register annotation config processors, if necessary.
   //注册注解配置(Annotation config)处理器
   if (this.includeAnnotationConfig) {
      AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
   }


   //返回注册的Bean个数
   return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}


/**
* Perform a scan within the specified base packages,
* returning the registered bean definitions.
* <p>This method does <i>not</i> register an annotation config processor
* but rather leaves this up to the caller.
* @param basePackages the packages to check for annotated classes
* @return set of beans registered if any for tooling registration purposes (never {@code null})
*/
//类路径Bean定义扫描器扫描给定包及其子包
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
   Assert.notEmpty(basePackages, "At least one base package must be specified");
   //创建一个集合,存放扫描到Bean定义的封装类
   Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
   //遍历扫描所有给定的包
   for (String basePackage : basePackages) {
      //调用父类ClassPathScanningCandidateComponentProvider的方法
      //扫描给定类路径,获取符合条件的Bean定义
      Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
      //遍历扫描到的Bean
      for (BeanDefinition candidate : candidates) {
         //获取Bean定义类中@Scope注解的值,即获取Bean的作用域
         ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
         //为Bean设置注解配置的作用域
         candidate.setScope(scopeMetadata.getScopeName());
         //为Bean生成名称
         String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
         //如果扫描到的Bean不是Spring的注解Bean,则为Bean设置默认值,
         //设置Bean的自动依赖注入装配属性等
         if (candidate instanceof AbstractBeanDefinition) {
            postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
         }
         //如果扫描到的Bean是Spring的注解Bean,则处理其通用的Spring注解
         if (candidate instanceof AnnotatedBeanDefinition) {
            //处理注解Bean中通用的注解,在分析注解Bean定义类读取器时已经分析过
            AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
         }
         //根据Bean名称检查指定的Bean是否需要在容器中注册,或者在容器中冲突
         if (checkCandidate(beanName, candidate)) {
            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
            //根据注解中配置的作用域,为Bean应用相应的代理模式
            definitionHolder =
                  AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            beanDefinitions.add(definitionHolder);
            //向容器注册扫描到的Bean
            registerBeanDefinition(definitionHolder, this.registry);
         }
      }
   }
   return beanDefinitions;
}

类路径 Bean 定义扫描器 ClassPathBeanDefinitionScanner 主要通过 findCandidateComponents()方法调用其父类 ClassPathScanningCandidateComponentProvider 类来扫描获取给定包及其子包下的类。

public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {


   static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";

   protected final Log logger = LogFactory.getLog(getClass());

   private String resourcePattern = DEFAULT_RESOURCE_PATTERN;


   //保存过滤规则要包含的注解,即Spring默认的@Component、@Repository、@Service、
   //@Controller注解的Bean,以及JavaEE6的@ManagedBean和JSR-330@Named注解
   private final List<TypeFilter> includeFilters = new LinkedList<>();

   //保存过滤规则要排除的注解
   private final List<TypeFilter> excludeFilters = new LinkedList<>();
   
   protected ClassPathScanningCandidateComponentProvider() {
   }


   
   //构造方法,该方法在子类ClassPathBeanDefinitionScanner的构造方法中被调用
   public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters) {
      this(useDefaultFilters, new StandardEnvironment());
   }

   public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, Environment environment) {
      //如果使用Spring默认的过滤规则,则向容器注册过滤规则
      if (useDefaultFilters) {
         registerDefaultFilters();
      }
      setEnvironment(environment);
      setResourceLoader(null);
   }

   public void setResourcePattern(String resourcePattern) {
      Assert.notNull(resourcePattern, "'resourcePattern' must not be null");
      this.resourcePattern = resourcePattern;
   }

   //向容器注册过滤规则
   @SuppressWarnings("unchecked")
   protected void registerDefaultFilters() {
      //向要包含的过滤规则中添加@Component注解类,注意Spring中@Repository
      //@Service@Controller都是Component,因为这些注解都添加了@Component注解
      this.includeFilters.add(new AnnotationTypeFilter(Component.class));
      //获取当前类的类加载器
      ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
      try {
         //向要包含的过滤规则添加JavaEE6的@ManagedBean注解
         this.includeFilters.add(new AnnotationTypeFilter(
               ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
         logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
      }
      catch (ClassNotFoundException ex) {
         // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
      }
      try {
         //向要包含的过滤规则添加@Named注解
         this.includeFilters.add(new AnnotationTypeFilter(
               ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
         logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
      }
      catch (ClassNotFoundException ex) {
         // JSR-330 API not available - simply skip.
      }
   }
   //扫描给定类路径的包
   public Set<BeanDefinition> findCandidateComponents(String basePackage) {
      if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
         return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
      }
      else {
         return scanCandidateComponents(basePackage);
      }
   }


   private Set<BeanDefinition> addCandidateComponentsFromIndex(CandidateComponentsIndex index, String basePackage) {
      //创建存储扫描到的类的集合
      Set<BeanDefinition> candidates = new LinkedHashSet<>();
      try {
         Set<String> types = new HashSet<>();
         for (TypeFilter filter : this.includeFilters) {
            String stereotype = extractStereotype(filter);
            if (stereotype == null) {
               throw new IllegalArgumentException("Failed to extract stereotype from "+ filter);
            }
            types.addAll(index.getCandidateTypes(basePackage, stereotype));
         }
         boolean traceEnabled = logger.isTraceEnabled();
         boolean debugEnabled = logger.isDebugEnabled();
         for (String type : types) {
            //为指定资源获取元数据读取器,元信息读取器通过汇编(ASM)//取资源元信息
            MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);
            //如果扫描到的类符合容器配置的过滤规则
            if (isCandidateComponent(metadataReader)) {
               //通过汇编(ASM)读取资源字节码中的Bean定义元信息
               AnnotatedGenericBeanDefinition sbd = new AnnotatedGenericBeanDefinition(
                     metadataReader.getAnnotationMetadata());
               if (isCandidateComponent(sbd)) {
                  if (debugEnabled) {
                     logger.debug("Using candidate component class from index: " + type);
                  }
                  candidates.add(sbd);
               }
               else {
                  if (debugEnabled) {
                     logger.debug("Ignored because not a concrete top-level class: " + type);
                  }
               }
            }
            else {
               if (traceEnabled) {
                  logger.trace("Ignored because matching an exclude filter: " + type);
               }
            }
         }
      }
      catch (IOException ex) {
         throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
      }
      return candidates;
   }

   //判断元信息读取器读取的类是否符合容器定义的注解过滤规则
   protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
      //如果读取的类的注解在排除注解过滤规则中,返回false
      for (TypeFilter tf : this.excludeFilters) {
         if (tf.match(metadataReader, getMetadataReaderFactory())) {
            return false;
         }
      }
      //如果读取的类的注解在包含的注解的过滤规则中,则返回ture
      for (TypeFilter tf : this.includeFilters) {
         if (tf.match(metadataReader, getMetadataReaderFactory())) {
            return isConditionMatch(metadataReader);
         }
      }
      //如果读取的类的注解既不在排除规则,也不在包含规则中,则返回false
      return false;
   }

}
  • 注册注解 BeanDefinition
    AnnotationConfigWebApplicationContext 是 AnnotationConfigApplicationContext 的 Web 版,它们对于注解 Bean 的注册和扫描是基本相同的,但是 AnnotationConfigWebApplicationContext对注解 Bean 定义的载入稍有不同,AnnotationConfigWebApplicationContext 注入注解 Bean 定义源码如下:
//载入注解Bean定义资源
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
   //为容器设置注解Bean定义读取器
   AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
   //为容器设置类路径Bean定义扫描器
   ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);


   //获取容器的Bean名称生成器
   BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
   //为注解Bean定义读取器和类路径扫描器设置Bean名称生成器
   if (beanNameGenerator != null) {
      reader.setBeanNameGenerator(beanNameGenerator);
      scanner.setBeanNameGenerator(beanNameGenerator);
      beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
   }


   //获取容器的作用域元信息解析器
   ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
   //为注解Bean定义读取器和类路径扫描器设置作用域元信息解析器
   if (scopeMetadataResolver != null) {
      reader.setScopeMetadataResolver(scopeMetadataResolver);
      scanner.setScopeMetadataResolver(scopeMetadataResolver);
   }


   if (!this.annotatedClasses.isEmpty()) {
      if (logger.isInfoEnabled()) {
         logger.info("Registering annotated classes: [" +
               StringUtils.collectionToCommaDelimitedString(this.annotatedClasses) + "]");
      }
      reader.register(this.annotatedClasses.toArray(new Class<?>[this.annotatedClasses.size()]));
   }


   if (!this.basePackages.isEmpty()) {
      if (logger.isInfoEnabled()) {
         logger.info("Scanning base packages: [" +
               StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
      }
      scanner.scan(this.basePackages.toArray(new String[this.basePackages.size()]));
   }


   //获取容器定义的Bean定义资源路径
   String[] configLocations = getConfigLocations();
   //如果定位的Bean定义资源路径不为空
   if (configLocations != null) {
      for (String configLocation : configLocations) {
         try {
            //使用当前容器的类加载器加载定位路径的字节码类文件
            Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
            if (logger.isInfoEnabled()) {
               logger.info("Successfully resolved class for [" + configLocation + "]");
            }
            reader.register(clazz);
         }
         catch (ClassNotFoundException ex) {
            if (logger.isDebugEnabled()) {
               logger.debug("Could not load class for config location [" + configLocation +
                     "] - trying package scan. " + ex);
            }
            //如果容器类加载器加载定义路径的Bean定义资源失败
            //则启用容器类路径扫描器扫描给定路径包及其子包中的类
            int count = scanner.scan(configLocation);
            if (logger.isInfoEnabled()) {
               if (count == 0) {
                  logger.info("No annotated classes found for specified class/package [" + configLocation + "]");
               }
               else {
                  logger.info("Found " + count + " annotated classes in package [" + configLocation + "]");
               }
            }
         }
      }
   }
}

四、Spring 依赖注入(DI)

  1. 依赖注入的关键类
  1. IOC容器 : BeanFactory getBean()、AbstractBeanFactory
  2. 实例化策略 :SimpleInstantiationStrategy
  3. 存储实例所有相关的信息scope、proxy、instance、BeanWrapper
  1. 依赖注入执行细节
    在这里插入图片描述

  2. 依赖注入发生的时间

当 Spring IOC 容器完成了 Bean 定义资源的定位、载入和解析注册以后,IOC 容器中已经管理类 Bean定义的相关数据,但是此时 IOC 容器还没有对所管理的 Bean 进行依赖注入,依赖注入在以下两种情况发生:

  1. 用户第一次调用 getBean()方法时,IOC 容器触发依赖注入。
  2. 当用户在配置文件中将元素配置了lazy-init=false 属性,即让容器在解析注册 Bean 定义时进行预实例化,触发依赖注入。

BeanFactory 接口定义了 Spring IOC 容器的基本功能规范,是 Spring IOC 容器所应遵守的最底层和最基本的编程规范。BeanFactory 接口中定义了几个 getBean()方法,就是用户向 IOC 容器索取管理的Bean 的方法,我们通过分析其子类的具体实现,理解 Spring IOC 容器在用户索取 Bean 时如何完成依赖注入。
在这里插入图片描述

在 BeanFactory 中我们可以看到 getBean(String…)方法,但它具体实现在 AbstractBeanFactory 中。

  1. 实例化过程
  • 寻找获取 Bean 的入口
    AbstractBeanFactory 的 getBean()相关方法的源码如下:
public interface BeanFactory {
   //对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
   //如果需要得到工厂本身,需要转义
   String FACTORY_BEAN_PREFIX = "&";

   //根据bean的名字,获取在IOC容器中得到bean实例
   Object getBean(String name) throws BeansException;

   //根据bean的名字和Class类型来得到bean实例,增加了类型安全验证机制。
   <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;

   <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

   //提供对bean的检索,看看是否在IOC容器有这个名字的bean
   boolean containsBean(String name);

   //根据bean名字得到bean实例,并同时判断这个bean是不是单例
   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;

   //得到bean实例的Class类型
   @Nullable
   Class<?> getType(String name) throws NoSuchBeanDefinitionException;

   //得到bean的别名,如果根据别名检索,那么其原名也会被检索出来
   String[] getAliases(String name);

}
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {

   //获取IOC容器中指定名称的Bean
   @Override
   public Object getBean(String name) throws BeansException {
      //doGetBean才是真正向IoC容器获取被管理Bean的过程
      return doGetBean(name, null, null, false);
   }


   //获取IOC容器中指定名称和类型的Bean
   @Override
   public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {
      //doGetBean才是真正向IoC容器获取被管理Bean的过程
      return doGetBean(name, requiredType, null, false);
   }


   //获取IOC容器中指定名称和参数的Bean
   @Override
   public Object getBean(String name, Object... args) throws BeansException {
      //doGetBean才是真正向IoC容器获取被管理Bean的过程
      return doGetBean(name, null, args, false);
   }
   //获取IOC容器中指定名称、类型和参数的Bean
   public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
         throws BeansException {
      //doGetBean才是真正向IoC容器获取被管理Bean的过程
      return doGetBean(name, requiredType, args, false);
   }

   @SuppressWarnings("unchecked")
   //真正实现向IOC容器获取Bean的功能,也是触发依赖注入功能的地方
   protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
         @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {


      //根据指定的名称获取被管理Bean的名称,剥离指定名称中对容器的相关依赖
      //如果指定的是别名,将别名转换为规范的Bean名称
      final String beanName = transformedBeanName(name);
      Object bean;


      // Eagerly check singleton cache for manually registered singletons.
      //先从缓存中取是否已经有被创建过的单态类型的Bean
      //对于单例模式的Bean整个IOC容器中只创建一次,不需要重复创建
      Object sharedInstance = getSingleton(beanName);
      //IOC容器创建单例模式Bean实例对象
      if (sharedInstance != null && args == null) {
         if (logger.isDebugEnabled()) {
            //如果指定名称的Bean在容器中已有单例模式的Bean被创建
            //直接返回已经创建的Bean
            if (isSingletonCurrentlyInCreation(beanName)) {
               logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                     "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
               logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
         }
         //获取给定Bean的实例对象,主要是完成FactoryBean的相关处理
         //注意:BeanFactory是管理容器中Bean的工厂,而FactoryBean是
         //创建创建对象的工厂Bean,两者之间有区别
         bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
      }


      else {
         // Fail if we're already creating this bean instance:
         // We're assumably within a circular reference.
         //缓存没有正在创建的单例模式Bean
         //缓存中已经有已经创建的原型模式Bean
         //但是由于循环引用的问题导致实例化对象失败
         if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
         }


         // Check if bean definition exists in this factory.
         //对IOC容器中是否存在指定名称的BeanDefinition进行检查,首先检查是否
         //能在当前的BeanFactory中获取的所需要的Bean,如果不能则委托当前容器
         //的父级容器去查找,如果还是找不到则沿着容器的继承体系向父级容器查找
         BeanFactory parentBeanFactory = getParentBeanFactory();
         //当前容器的父级容器存在,且当前容器中不存在指定名称的Bean
         if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // Not found -> check parent.
            //解析指定Bean名称的原始名称
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
               return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                     nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if (args != null) {
               // Delegation to parent with explicit args.
               //委派父级容器根据指定名称和显式的参数查找
               return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else {
               // No args -> delegate to standard getBean method.
               //委派父级容器根据指定名称和类型查找
               return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
         }


         //创建的Bean是否需要进行类型验证,一般不需要
         if (!typeCheckOnly) {
            //向容器标记指定的Bean已经被创建
            markBeanAsCreated(beanName);
         }


         try {
            //根据指定Bean名称获取其父级的Bean定义
            //主要解决Bean继承时子类合并父类公共属性问题
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);


            // Guarantee initialization of beans that the current bean depends on.
            //获取当前Bean所有依赖Bean的名称
            String[] dependsOn = mbd.getDependsOn();
            //如果当前Bean有依赖Bean
            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 + "'");
                  }
                  //递归调用getBean方法,获取当前Bean的依赖Bean
                  registerDependentBean(dep, beanName);
                  //把被依赖Bean注册给当前依赖的Bean
                  getBean(dep);
               }
            }


            // Create bean instance.
            //创建单例模式Bean的实例对象
            if (mbd.isSingleton()) {
               //这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
               sharedInstance = getSingleton(beanName, () -> {
                  try {
                     //创建一个指定Bean实例对象,如果有父级继承,则合并子类和父类的定义
                     return createBean(beanName, mbd, args);
                  }
                  catch (BeansException ex) {
                     // Explicitly remove instance from singleton cache: It might have been put there
                     // eagerly by the creation process, to allow for circular reference resolution.
                     // Also remove any beans that received a temporary reference to the bean.
                     //显式地从容器单例模式Bean缓存中清除实例对象
                     destroySingleton(beanName);
                     throw ex;
                  }
               });
               //获取给定Bean的实例对象
               bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }


            //IOC容器创建原型模式Bean实例对象
            else if (mbd.isPrototype()) {
               // It's a prototype -> create a new instance.
               //原型模式(Prototype)是每次都会创建一个新的对象
               Object prototypeInstance = null;
               try {
                  //回调beforePrototypeCreation方法,默认的功能是注册当前创建的原型对象
                  beforePrototypeCreation(beanName);
                  //创建指定Bean对象实例
                  prototypeInstance = createBean(beanName, mbd, args);
               }
               finally {
                  //回调afterPrototypeCreation方法,默认的功能告诉IOC容器指定Bean的原型对象不再创建
                  afterPrototypeCreation(beanName);
               }
               //获取给定Bean的实例对象
               bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }


            //要创建的Bean既不是单例模式,也不是原型模式,则根据Bean定义资源中
            //配置的生命周期范围,选择实例化Bean的合适方法,这种在Web应用程序中
            //比较常用,如:request、session、application等生命周期
            else {
               String scopeName = mbd.getScope();
               final Scope scope = this.scopes.get(scopeName);
               //Bean定义资源中没有配置生命周期范围,则Bean定义不合法
               if (scope == null) {
                  throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
               }
               try {
                  //这里又使用了一个匿名内部类,获取一个指定生命周期范围的实例
                  Object scopedInstance = scope.get(beanName, () -> {
                     beforePrototypeCreation(beanName);
                     try {
                        return createBean(beanName, mbd, args);
                     }
                     finally {
                        afterPrototypeCreation(beanName);
                     }
                  });
                  //获取给定Bean的实例对象
                  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;
         }
      }


      // Check if required type matches the type of the actual bean instance.
      //对创建的Bean实例对象进行类型检查
      if (requiredType != null && !requiredType.isInstance(bean)) {
         try {
            T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
            if (convertedBean == null) {
               throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
            return convertedBean;
         }
         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;
   }


   //获取给定Bean的实例对象,主要是完成FactoryBean的相关处理
   protected Object getObjectForBeanInstance(
         Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {


      // Don't let calling code try to dereference the factory if the bean isn't a factory.
      //容器已经得到了Bean实例对象,这个实例对象可能是一个普通的Bean,
      //也可能是一个工厂Bean,如果是一个工厂Bean,则使用它创建一个Bean实例对象,
      //如果调用本身就想获得一个容器的引用,则指定返回这个工厂Bean实例对象
      //如果指定的名称是容器的解引用(dereference,即是对象本身而非内存地址),
      //且Bean实例也不是创建Bean实例对象的工厂Bean
      if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
         throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
      }


      // Now we have the bean instance, which may be a normal bean or a FactoryBean.
      // If it's a FactoryBean, we use it to create a bean instance, unless the
      // caller actually wants a reference to the factory.
      //如果Bean实例不是工厂Bean,或者指定名称是容器的解引用,
      //调用者向获取对容器的引用,则直接返回当前的Bean实例
      if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
         return beanInstance;
      }


      //处理指定名称不是容器的解引用,或者根据名称获取的Bean实例对象是一个工厂Bean
      //使用工厂Bean创建一个Bean的实例对象
      Object object = null;
      if (mbd == null) {
         //从Bean工厂缓存中获取给定名称的Bean实例对象
         object = getCachedObjectForFactoryBean(beanName);
      }
      //让Bean工厂生产给定名称的Bean对象实例
      if (object == null) {
         // Return bean instance from factory.
         FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
         // Caches object obtained from FactoryBean if it is a singleton.
         //如果从Bean工厂生产的Bean是单态模式的,则缓存
         if (mbd == null && containsBeanDefinition(beanName)) {
            //从容器中获取指定名称的Bean定义,如果继承基类,则合并基类相关属性
            mbd = getMergedLocalBeanDefinition(beanName);
         }
         //如果从容器得到Bean定义信息,并且Bean定义信息不是虚构的,
         //则让工厂Bean生产Bean实例对象
         boolean synthetic = (mbd != null && mbd.isSynthetic());
         //调用FactoryBeanRegistrySupport类的getObjectFromFactoryBean方法,
         //实现工厂Bean生产Bean对象实例的过程
         object = getObjectFromFactoryBean(factory, beanName, !synthetic);
      }
      return object;
   }
}

通过上面对向 IOC 容器获取 Bean 方法的分析,我们可以看到在 Spring 中,如果 Bean 定义的单例模式(Singleton),则容器在创建之前先从缓存中查找,以确保整个容器中只存在一个实例对象。如果 Bean定义的是原型模式(Prototype),则容器每次都会创建一个新的实例对象。除此之外,Bean 定义还可以扩展为指定其生命周期范围。上面的源码只是定义了根据 Bean 定义的模式,采取的不同创建 Bean 实例对象的策略,具体的 Bean实例对象的创建过程由实现了 BeanFactory 接口的匿名内部类的 createBean()方法完成,BeanFactory 使用委派模式 , 具体的 Bean 实例创建过程交由其实现类AbstractAutowireCapableBeanFactory 完成,我们继续分析 AbstractAutowireCapableBeanFactory的 createBean()方法的源码,理解其创建 Bean 实例的具体实现过程。

  • 开始实例化

AbstractAutowireCapableBeanFactory 类实现了 BeanFactory 接口,创建容器指定的 Bean 实例对象,同时还对创建的 Bean 实例对象进行初始化处理。其创建 Bean 实例对象的方法源码如下:

//创建Bean实例对象
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {


   if (logger.isDebugEnabled()) {
      logger.debug("Creating instance of bean '" + beanName + "'");
   }
   RootBeanDefinition mbdToUse = mbd;


   // Make sure bean class is actually resolved at this point, and
   // clone the bean definition in case of a dynamically resolved Class
   // which cannot be stored in the shared merged bean definition.
   //判断需要创建的Bean是否可以实例化,即是否可以通过当前的类加载器加载
   Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
   if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
      mbdToUse = new RootBeanDefinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
   }


   // Prepare method overrides.
   //校验和准备Bean中的方法覆盖
   try {
      mbdToUse.prepareMethodOverrides();
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
            beanName, "Validation of method overrides failed", ex);
   }


   try {
      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      //如果Bean配置了初始化前和初始化后的处理器,则试图返回一个需要创建Bean的代理对象
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
         return bean;
      }
   }
   catch (Throwable ex) {
      throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
            "BeanPostProcessor before instantiation of bean failed", ex);
   }


   try {
      //创建Bean的入口
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      if (logger.isDebugEnabled()) {
         logger.debug("Finished creating instance of bean '" + beanName + "'");
      }
      return beanInstance;
   }
   catch (BeanCreationException ex) {
      // A previously detected exception with proper bean creation context already...
      throw ex;
   }
   catch (ImplicitlyAppearedSingletonException ex) {
      // An IllegalStateException to be communicated up to DefaultSingletonBeanRegistry...
      throw ex;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
   }
}

//真正创建Bean的方法
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {


   // Instantiate the bean.
   //封装被创建的Bean对象
   BeanWrapper instanceWrapper = null;
   if (mbd.isSingleton()) {
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   if (instanceWrapper == null) {
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   final Object bean = instanceWrapper.getWrappedInstance();
   //获取实例化对象的类型
   Class<?> beanType = instanceWrapper.getWrappedClass();
   if (beanType != NullBean.class) {
      mbd.resolvedTargetType = beanType;
   }


   // Allow post-processors to modify the merged bean definition.
   //调用PostProcessor后置处理器
   synchronized (mbd.postProcessingLock) {
      if (!mbd.postProcessed) {
         try {
            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.
   //向容器中缓存单例模式的Bean对象,以防循环引用
   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, () -> getEarlyBeanReference(beanName, mbd, bean));
   }


   // Initialize the bean instance.
   //Bean对象的初始化,依赖注入在此触发
   //这个exposedObject在初始化完成之后返回作为依赖注入完成后的Bean
   Object exposedObject = bean;
   try {
      //将Bean实例对象封装,并且Bean定义中配置的属性值赋值给实例对象
      populateBean(beanName, mbd, instanceWrapper);
      //初始化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) {
      //获取指定名称的已注册的单例模式Bean对象
      Object earlySingletonReference = getSingleton(beanName, false);
      if (earlySingletonReference != null) {
         //根据名称获取的已注册的Bean和正在实例化的Bean是同一个
         if (exposedObject == bean) {
            //当前实例化的Bean初始化完成
            exposedObject = earlySingletonReference;
         }
         //当前Bean依赖其他Bean,并且当发生循环引用时不允许新创建实例对象
         else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
            String[] dependentBeans = getDependentBeans(beanName);
            Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
            //获取当前Bean所依赖的其他Bean
            for (String dependentBean : dependentBeans) {
               //对依赖Bean进行类型检查
               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.
   //注册完成依赖注入的Bean
   try {
      registerDisposableBeanIfNecessary(beanName, bean, mbd);
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
   }


   return exposedObject;
}

通过上面的源码注释,我们看到具体的依赖注入实现其实就在以下两个方法中:

  1. createBeanInstance()方法,生成 Bean 所包含的 java 对象实例。
  2. populateBean()方法,对 Bean 属性的依赖注入进行处理。

下面继续分析这两个方法的代码实现:

  • 选择 Bean 实例化策略
    在 createBeanInstance()方法中,根据指定的初始化策略,使用简单工厂、工厂方法或者容器的自动装配特性生成 Java 实例对象,创建对象的源码如下:
//创建Bean的实例对象
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   // Make sure bean class is actually resolved at this point.
   //检查确认Bean是可实例化的
   Class<?> beanClass = resolveBeanClass(mbd, beanName);


   //使用工厂方法对Bean进行实例化
   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)  {
      //调用工厂方法实例化
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }


   // Shortcut when re-creating the same 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) {
         //配置了自动装配属性,使用容器的自动装配实例化
         //容器的自动装配是根据参数类型匹配Bean的构造方法
         return autowireConstructor(beanName, mbd, null, null);
      }
      else {
         //使用默认的无参构造方法实例化
         return instantiateBean(beanName, mbd);
      }
   }


   // Need to determine the constructor...
   //使用Bean的构造方法进行实例化
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   if (ctors != null ||
         mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
      //使用容器的自动装配特性,调用匹配的构造方法实例化
      return autowireConstructor(beanName, mbd, ctors, args);
   }

   // No special handling: simply use no-arg constructor.
   //使用默认的无参构造方法实例化
   return instantiateBean(beanName, mbd);
}

//使用默认的无参构造方法实例化Bean对象
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
   try {
      Object beanInstance;
      final BeanFactory parent = this;
      //获取系统的安全管理接口,JDK标准的安全管理API
      if (System.getSecurityManager() != null) {
         //这里是一个匿名内置类,根据实例化策略创建实例对象
         beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
               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);
   }
}

经过对上面的代码分析,我们可以看出,对使用工厂方法和自动装配特性的 Bean 的实例化相当比较清楚,调用相应的工厂方法或者参数匹配的构造方法即可完成实例化对象的工作,但是对于我们最常使用的默认无参构造方法就需要使用相应的初始化策略(JDK 的反射机制或者 CGLib)来进行初始化了,在方法 getInstantiationStrategy().instantiate()中就具体实现类使用初始策略实例化对象。

  • 执行 Bean 实例化
    在使用默认的无参构造方法创建 Bean 的实例化对象时,方法 getInstantiationStrategy().instantiate()调用了 SimpleInstantiationStrategy 类中的实例化 Bean 的方法,其源码如下:
//使用初始化策略实例化Bean对象
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
   // Don't override the class with CGLIB if no overrides.
   //如果Bean定义中没有方法覆盖,则就不需要CGLIB父类类的方法
   if (!bd.hasMethodOverrides()) {
      Constructor<?> constructorToUse;
      synchronized (bd.constructorArgumentLock) {
         //获取对象的构造方法或工厂方法
         constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
         //如果没有构造方法且没有工厂方法
         if (constructorToUse == null) {
            //使用JDK的反射机制,判断要实例化的Bean是否是接口
            final Class<?> clazz = bd.getBeanClass();
            if (clazz.isInterface()) {
               throw new BeanInstantiationException(clazz, "Specified class is an interface");
            }
            try {
               if (System.getSecurityManager() != null) {
                  //这里是一个匿名内置类,使用反射机制获取Bean的构造方法
                  constructorToUse = AccessController.doPrivileged(
                        (PrivilegedExceptionAction<Constructor<?>>) () -> clazz.getDeclaredConstructor());
               }
               else {
                  constructorToUse = clazz.getDeclaredConstructor();
               }
               bd.resolvedConstructorOrFactoryMethod = constructorToUse;
            }
            catch (Throwable ex) {
               throw new BeanInstantiationException(clazz, "No default constructor found", ex);
            }
         }
      }
      //使用BeanUtils实例化,通过反射机制调用”构造方法.newInstance(arg)”来进行实例化
      return BeanUtils.instantiateClass(constructorToUse);
   }
   else {
      // Must generate CGLIB subclass.
      //使用CGLIB来实例化对象
      return instantiateWithMethodInjection(bd, beanName, owner);
   }
}

通过上面的代码分析,我们看到了如果 Bean 有方法被覆盖了,则使用 JDK 的反射机制进行实例化,否则,使用 CGLib 进行实例化。
instantiateWithMethodInjection() 方法调用 SimpleInstantiationStrategy 的子类CGLibSubclassingInstantiationStrategy 使用 CGLib 来进行初始化,其源码如下:

//使用CGLIB进行Bean对象实例化
   public Object instantiate(@Nullable Constructor<?> ctor, @Nullable Object... args) {
      //创建代理子类
      Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
      Object instance;
      if (ctor == null) {
         instance = BeanUtils.instantiateClass(subclass);
      }
      else {
         try {
            Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
            instance = enhancedSubclassConstructor.newInstance(args);
         }
         catch (Exception ex) {
            throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
                  "Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
         }
      }
      // SPR-10785: set callbacks directly on the instance instead of in the
      // enhanced class (via the Enhancer) in order to avoid memory leaks.
      Factory factory = (Factory) instance;
      factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
            new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
            new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
      return instance;
   }


   /**
    * Create an enhanced subclass of the bean class for the provided bean
    * definition, using CGLIB.
    */
   private Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) {
      //CGLIB中的类
      Enhancer enhancer = new Enhancer();
      //将Bean本身作为其基类
      enhancer.setSuperclass(beanDefinition.getBeanClass());
      enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
      if (this.owner instanceof ConfigurableBeanFactory) {
         ClassLoader cl = ((ConfigurableBeanFactory) this.owner).getBeanClassLoader();
         enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(cl));
      }
      enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));
      enhancer.setCallbackTypes(CALLBACK_TYPES);
      //使用CGLIB的createClass方法生成实例对象
      return enhancer.createClass();
   }
}

CGLib 是一个常用的字节码生成器的类库,它提供了一系列 API 实现 Java 字节码的生成和转换功能。我们在学习 JDK 的动态代理时都知道,JDK 的动态代理只能针对接口,如果一个类没有实现任何接口,要对其进行动态代理只能使用 CGLib。

  • 准备依赖注入

在前面的分析中我们已经了解到 Bean 的依赖注入主要分为两个步骤,首先调用 createBeanInstance()方法生成 Bean 所包含的 Java 对象实例。然后,调用 populateBean()方法,对 Bean 属性的依赖注入进行处理。

上面我们已经分析了容器初始化生成 Bean 所包含的 Java 实例对象的过程,现在我们继续分析生成对象后,Spring IOC 容器是如何将 Bean 的属性依赖关系注入 Bean 实例对象中并设置好的,回到AbstractAutowireCapableBeanFactory 的 populateBean()方法,对属性依赖注入的代码如下:

//将Bean属性设置到生成的实例对象上
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   if (bw == null) {
      if (mbd.hasPropertyValues()) {
         throw new BeanCreationException(
               mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
      }
      else {
         // Skip property population phase for null instance.
         return;
      }
   }


   // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
   // state of the bean before properties are set. This can be used, for example,
   // to support styles of field injection.
   boolean continueWithPropertyPopulation = true;


   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
               continueWithPropertyPopulation = false;
               break;
            }
         }
      }
   }


   if (!continueWithPropertyPopulation) {
      return;
   }
   //获取容器在解析Bean定义资源时为BeanDefiniton中设置的属性值
   PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);


   //对依赖注入处理,首先处理autowiring自动装配的依赖注入
   if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
         mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);


      // Add property values based on autowire by name if applicable.
      //根据Bean名称进行autowiring自动装配处理
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
         autowireByName(beanName, mbd, bw, newPvs);
      }


      // Add property values based on autowire by type if applicable.
      //根据Bean类型进行autowiring自动装配处理
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
         autowireByType(beanName, mbd, bw, newPvs);
      }


      pvs = newPvs;
   }


   //对非autowiring的属性进行依赖注入处理


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


   if (hasInstAwareBpps || needsDepCheck) {
      if (pvs == null) {
         pvs = mbd.getPropertyValues();
      }
      PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      if (hasInstAwareBpps) {
         for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
               InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
               pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
               if (pvs == null) {
                  return;
               }
            }
         }
      }
      if (needsDepCheck) {
         checkDependencies(beanName, mbd, filteredPds, pvs);
      }
   }


   if (pvs != null) {
      //对属性进行注入
      applyPropertyValues(beanName, mbd, bw, pvs);
   }
}

//解析并注入依赖属性的过程
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
   if (pvs.isEmpty()) {
      return;
   }


   //封装属性值
   MutablePropertyValues mpvs = null;
   List<PropertyValue> original;


   if (System.getSecurityManager() != null) {
      if (bw instanceof BeanWrapperImpl) {
         //设置安全上下文,JDK安全机制
         ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
      }
   }


   if (pvs instanceof MutablePropertyValues) {
      mpvs = (MutablePropertyValues) pvs;
      //属性值已经转换
      if (mpvs.isConverted()) {
         // Shortcut: use the pre-converted values as-is.
         try {
            //为实例化对象设置属性值
            bw.setPropertyValues(mpvs);
            return;
         }
         catch (BeansException ex) {
            throw new BeanCreationException(
                  mbd.getResourceDescription(), beanName, "Error setting property values", ex);
         }
      }
      //获取属性值对象的原始类型值
      original = mpvs.getPropertyValueList();
   }
   else {
      original = Arrays.asList(pvs.getPropertyValues());
   }


   //获取用户自定义的类型转换
   TypeConverter converter = getCustomTypeConverter();
   if (converter == null) {
      converter = bw;
   }
   //创建一个Bean定义属性值解析器,将Bean定义中的属性值解析为Bean实例对象的实际值
   BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);


   // Create a deep copy, resolving any references for values.


   //为属性的解析值创建一个拷贝,将拷贝的数据注入到实例对象中
   List<PropertyValue> deepCopy = new ArrayList<>(original.size());
   boolean resolveNecessary = false;
   for (PropertyValue pv : original) {
      //属性值不需要转换
      if (pv.isConverted()) {
         deepCopy.add(pv);
      }
      //属性值需要转换
      else {
         String propertyName = pv.getName();
         //原始的属性值,即转换之前的属性值
         Object originalValue = pv.getValue();
         //转换属性值,例如将引用转换为IOC容器中实例化对象引用
         Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
         //转换之后的属性值
         Object convertedValue = resolvedValue;
         //属性值是否可以转换
         boolean convertible = bw.isWritableProperty(propertyName) &&
               !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
         if (convertible) {
            //使用用户自定义的类型转换器转换属性值
            convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
         }
         // Possibly store converted value in merged bean definition,
         // in order to avoid re-conversion for every created bean instance.
         //存储转换后的属性值,避免每次属性注入时的转换工作
         if (resolvedValue == originalValue) {
            if (convertible) {
               //设置属性转换之后的值
               pv.setConvertedValue(convertedValue);
            }
            deepCopy.add(pv);
         }
         //属性是可转换的,且属性原始值是字符串类型,且属性的原始类型值不是
         //动态生成的字符串,且属性的原始值不是集合或者数组类型
         else if (convertible && originalValue instanceof TypedStringValue &&
               !((TypedStringValue) originalValue).isDynamic() &&
               !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
            pv.setConvertedValue(convertedValue);
            //重新封装属性的值
            deepCopy.add(pv);
         }
         else {
            resolveNecessary = true;
            deepCopy.add(new PropertyValue(pv, convertedValue));
         }
      }
   }
   if (mpvs != null && !resolveNecessary) {
      //标记属性值已经转换过
      mpvs.setConverted();
   }


   // Set our (possibly massaged) deep copy.
   //进行属性依赖注入
   try {
      bw.setPropertyValues(new MutablePropertyValues(deepCopy));
   }
   catch (BeansException ex) {
      throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Error setting property values", ex);
   }
}

分析上述代码,我们可以看出,对属性的注入过程分以下两种情况:

  1. 属性值类型不需要强制转换时,不需要解析属性值,直接准备进行依赖注入。
  2. 属性值需要进行类型强制转换时,如对其他对象的引用等,首先需要解析属性值,然后对解析后的属性值进行依赖注入。

对属性值的解析是在 BeanDefinitionValueResolver 类中的 resolveValueIfNecessary()方法中进行的,对属性值的依赖注入是通过 bw.setPropertyValues()方法实现的,在分析属性值的依赖注入之前,我们先分析一下对属性值的解析过程。

  • 解析属性注入规则

当容器在对属性进行依赖注入时,如果发现属性值需要进行类型转换,如属性值是容器中另一个 Bean实例对象的引用,则容器首先需要根据属性值解析出所引用的对象,然后才能将该引用对象注入到目标实例对象的属性上去,对属性进行解析的由 resolveValueIfNecessary()方法实现,其源码如下:

//解析属性值,对注入类型进行转换
@Nullable
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
   // We must check each value to see whether it requires a runtime reference
   // to another bean to be resolved.
   //对引用类型的属性进行解析
   if (value instanceof RuntimeBeanReference) {
      RuntimeBeanReference ref = (RuntimeBeanReference) value;
      //调用引用类型属性的解析方法
      return resolveReference(argName, ref);
   }
   //对属性值是引用容器中另一个Bean名称的解析
   else if (value instanceof RuntimeBeanNameReference) {
      String refName = ((RuntimeBeanNameReference) value).getBeanName();
      refName = String.valueOf(doEvaluate(refName));
      //从容器中获取指定名称的Bean
      if (!this.beanFactory.containsBean(refName)) {
         throw new BeanDefinitionStoreException(
               "Invalid bean name '" + refName + "' in bean reference for " + argName);
      }
      return refName;
   }
   //对Bean类型属性的解析,主要是Bean中的内部类
   else if (value instanceof BeanDefinitionHolder) {
      // Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
      BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
      return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
   }
   else if (value instanceof BeanDefinition) {
      // Resolve plain BeanDefinition, without contained name: use dummy name.
      BeanDefinition bd = (BeanDefinition) value;
      String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
            ObjectUtils.getIdentityHexString(bd);
      return resolveInnerBean(argName, innerBeanName, bd);
   }
   //对集合数组类型的属性解析
   else if (value instanceof ManagedArray) {
      // May need to resolve contained runtime references.
      ManagedArray array = (ManagedArray) value;
      //获取数组的类型
      Class<?> elementType = array.resolvedElementType;
      if (elementType == null) {
         //获取数组元素的类型
         String elementTypeName = array.getElementTypeName();
         if (StringUtils.hasText(elementTypeName)) {
            try {
               //使用反射机制创建指定类型的对象
               elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());
               array.resolvedElementType = elementType;
            }
            catch (Throwable ex) {
               // Improve the message by showing the context.
               throw new BeanCreationException(
                     this.beanDefinition.getResourceDescription(), this.beanName,
                     "Error resolving array type for " + argName, ex);
            }
         }
         //没有获取到数组的类型,也没有获取到数组元素的类型
         //则直接设置数组的类型为Object
         else {
            elementType = Object.class;
         }
      }
      //创建指定类型的数组
      return resolveManagedArray(argName, (List<?>) value, elementType);
   }
   //解析list类型的属性值
   else if (value instanceof ManagedList) {
      // May need to resolve contained runtime references.
      return resolveManagedList(argName, (List<?>) value);
   }
   //解析set类型的属性值
   else if (value instanceof ManagedSet) {
      // May need to resolve contained runtime references.
      return resolveManagedSet(argName, (Set<?>) value);
   }
   //解析map类型的属性值
   else if (value instanceof ManagedMap) {
      // May need to resolve contained runtime references.
      return resolveManagedMap(argName, (Map<?, ?>) value);
   }
   //解析props类型的属性值,props其实就是key和value均为字符串的map
   else if (value instanceof ManagedProperties) {
      Properties original = (Properties) value;
      //创建一个拷贝,用于作为解析后的返回值
      Properties copy = new Properties();
      original.forEach((propKey, propValue) -> {
         if (propKey instanceof TypedStringValue) {
            propKey = evaluate((TypedStringValue) propKey);
         }
         if (propValue instanceof TypedStringValue) {
            propValue = evaluate((TypedStringValue) propValue);
         }
         if (propKey == null || propValue == null) {
            throw new BeanCreationException(
                  this.beanDefinition.getResourceDescription(), this.beanName,
                  "Error converting Properties key/value pair for " + argName + ": resolved to null");
         }
         copy.put(propKey, propValue);
      });
      return copy;
   }
   //解析字符串类型的属性值
   else if (value instanceof TypedStringValue) {
      // Convert value to target type here.
      TypedStringValue typedStringValue = (TypedStringValue) value;
      Object valueObject = evaluate(typedStringValue);
      try {
         //获取属性的目标类型
         Class<?> resolvedTargetType = resolveTargetType(typedStringValue);
         if (resolvedTargetType != null) {
            //对目标类型的属性进行解析,递归调用
            return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
         }
         //没有获取到属性的目标对象,则按Object类型返回
         else {
            return valueObject;
         }
      }
      catch (Throwable ex) {
         // Improve the message by showing the context.
         throw new BeanCreationException(
               this.beanDefinition.getResourceDescription(), this.beanName,
               "Error converting typed String value for " + argName, ex);
      }
   }
   else if (value instanceof NullBean) {
      return null;
   }
   else {
      return evaluate(value);
   }
}

//解析引用类型的属性值
@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
   try {
      Object bean;
      //获取引用的Bean名称
      String refName = ref.getBeanName();
      refName = String.valueOf(doEvaluate(refName));
      //如果引用的对象在父类容器中,则从父类容器中获取指定的引用对象
      if (ref.isToParent()) {
         if (this.beanFactory.getParentBeanFactory() == null) {
            throw new BeanCreationException(
                  this.beanDefinition.getResourceDescription(), this.beanName,
                  "Can't resolve reference to bean '" + refName +
                  "' in parent factory: no parent factory available");
         }
         bean = this.beanFactory.getParentBeanFactory().getBean(refName);
      }
      //从当前的容器中获取指定的引用Bean对象,如果指定的Bean没有被实例化
      //则会递归触发引用Bean的初始化和依赖注入
      else {
         bean = this.beanFactory.getBean(refName);
         //将当前实例化对象的依赖引用对象
         this.beanFactory.registerDependentBean(refName, this.beanName);
      }
      if (bean instanceof NullBean) {
         bean = null;
      }
      return bean;
   }
   catch (BeansException ex) {
      throw new BeanCreationException(
            this.beanDefinition.getResourceDescription(), this.beanName,
            "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
   }
}


/**
* For each element in the managed array, resolve reference if necessary.
*/
//解析array类型的属性
private Object resolveManagedArray(Object argName, List<?> ml, Class<?> elementType) {
   //创建一个指定类型的数组,用于存放和返回解析后的数组
   Object resolved = Array.newInstance(elementType, ml.size());
   for (int i = 0; i < ml.size(); i++) {
      //递归解析array的每一个元素,并将解析后的值设置到resolved数组中,索引为i
      Array.set(resolved, i,
            resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i)));
   }
   return resolved;
}


/**
* For each element in the managed list, resolve reference if necessary.
*/
//解析list类型的属性
private List<?> resolveManagedList(Object argName, List<?> ml) {
   List<Object> resolved = new ArrayList<>(ml.size());
   for (int i = 0; i < ml.size(); i++) {
      //递归解析list的每一个元素
      resolved.add(
            resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i)));
   }
   return resolved;
}


/**
* For each element in the managed set, resolve reference if necessary.
*/
//解析set类型的属性
private Set<?> resolveManagedSet(Object argName, Set<?> ms) {
   Set<Object> resolved = new LinkedHashSet<>(ms.size());
   int i = 0;
   //递归解析set的每一个元素
   for (Object m : ms) {
      resolved.add(resolveValueIfNecessary(new KeyedArgName(argName, i), m));
      i++;
   }
   return resolved;
}


/**
* For each element in the managed map, resolve reference if necessary.
*/
//解析map类型的属性
private Map<?, ?> resolveManagedMap(Object argName, Map<?, ?> mm) {
   Map<Object, Object> resolved = new LinkedHashMap<>(mm.size());
   //递归解析map中每一个元素的key和value
   for (Map.Entry<?, ?> entry : mm.entrySet()) {
      Object resolvedKey = resolveValueIfNecessary(argName, entry.getKey());
      Object resolvedValue = resolveValueIfNecessary(
            new KeyedArgName(argName, entry.getKey()), entry.getValue());
      resolved.put(resolvedKey, resolvedValue);
   }
   return resolved;
}

通过上面的代码分析,我们明白了 Spring 是如何将引用类型,内部类以及集合类型等属性进行解析的,属性值解析完成后就可以进行依赖注入了,依赖注入的过程就是 Bean 对象实例设置到它所依赖的 Bean对象属性上去。而真正的依赖注入是通过 bw.setPropertyValues()方法实现的,该方法也使用了委托模式 ,在 BeanWrapper 接 口 中 至 少 定 义 了 方 法 声 明 , 依 赖 注 入 的 具 体 实 现 交 由 其 实 现 类BeanWrapperImpl 来完成,下面我们就分析依 BeanWrapperImpl 中赖注入相关的源码。

  • 注入赋值
    BeanWrapperImpl 类主要是对容器中完成初始化的 Bean 实例对象进行属性的依赖注入,即把 Bean对象设置到它所依赖的另一个 Bean 的属性中去。然而,BeanWrapperImpl 中的注入方法实际上由AbstractNestablePropertyAccessor 来实现的,其相关源码如下:
//实现属性依赖注入功能
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
   if (tokens.keys != null) {
      processKeyedProperty(tokens, pv);
   }
   else {
      processLocalProperty(tokens, pv);
   }
}


//实现属性依赖注入功能
@SuppressWarnings("unchecked")
private void processKeyedProperty(PropertyTokenHolder tokens, PropertyValue pv) {
   //调用属性的getter方法,获取属性的值
   Object propValue = getPropertyHoldingValue(tokens);
   PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
   if (ph == null) {
      throw new InvalidPropertyException(
            getRootClass(), this.nestedPath + tokens.actualName, "No property handler found");
   }
   Assert.state(tokens.keys != null, "No token keys");
   String lastKey = tokens.keys[tokens.keys.length - 1];


   //注入array类型的属性值
   if (propValue.getClass().isArray()) {
      Class<?> requiredType = propValue.getClass().getComponentType();
      int arrayIndex = Integer.parseInt(lastKey);
      Object oldValue = null;
      try {
         if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
            oldValue = Array.get(propValue, arrayIndex);
         }
         Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
               requiredType, ph.nested(tokens.keys.length));
         //获取集合类型属性的长度
         int length = Array.getLength(propValue);
         if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {
            Class<?> componentType = propValue.getClass().getComponentType();
            Object newArray = Array.newInstance(componentType, arrayIndex + 1);
            System.arraycopy(propValue, 0, newArray, 0, length);
            setPropertyValue(tokens.actualName, newArray);
            //调用属性的getter方法,获取属性的值
            propValue = getPropertyValue(tokens.actualName);
         }
         //将属性的值赋值给数组中的元素
         Array.set(propValue, arrayIndex, convertedValue);
      }
      catch (IndexOutOfBoundsException ex) {
         throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
               "Invalid array index in property path '" + tokens.canonicalName + "'", ex);
      }
   }


   //注入list类型的属性值
   else if (propValue instanceof List) {
      //获取list集合的类型
      Class<?> requiredType = ph.getCollectionType(tokens.keys.length);
      List<Object> list = (List<Object>) propValue;
      //获取list集合的size
      int index = Integer.parseInt(lastKey);
      Object oldValue = null;
      if (isExtractOldValueForEditor() && index < list.size()) {
         oldValue = list.get(index);
      }
      //获取list解析后的属性值
      Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
            requiredType, ph.nested(tokens.keys.length));
      int size = list.size();
      //如果list的长度大于属性值的长度,则多余的元素赋值为null
      if (index >= size && index < this.autoGrowCollectionLimit) {
         for (int i = size; i < index; i++) {
            try {
               list.add(null);
            }
            catch (NullPointerException ex) {
               throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
                     "Cannot set element with index " + index + " in List of size " +
                     size + ", accessed using property path '" + tokens.canonicalName +
                     "': List does not support filling up gaps with null elements");
            }
         }
         list.add(convertedValue);
      }
      else {
         try {
            //将值添加到list中
            list.set(index, convertedValue);
         }
         catch (IndexOutOfBoundsException ex) {
            throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
                  "Invalid list index in property path '" + tokens.canonicalName + "'", ex);
         }
      }
   }


   //注入map类型的属性值
   else if (propValue instanceof Map) {
      //获取map集合key的类型
      Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length);
      //获取map集合value的类型
      Class<?> mapValueType = ph.getMapValueType(tokens.keys.length);
      Map<Object, Object> map = (Map<Object, Object>) propValue;
      // IMPORTANT: Do not pass full property name in here - property editors
      // must not kick in for map keys but rather only for map values.
      TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);
      //解析map类型属性key值
      Object convertedMapKey = convertIfNecessary(null, null, lastKey, mapKeyType, typeDescriptor);
      Object oldValue = null;
      if (isExtractOldValueForEditor()) {
         oldValue = map.get(convertedMapKey);
      }
      // Pass full property name and old value in here, since we want full
      // conversion ability for map values.
      //解析map类型属性value值
      Object convertedMapValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
            mapValueType, ph.nested(tokens.keys.length));
      //将解析后的key和value值赋值给map集合属性
      map.put(convertedMapKey, convertedMapValue);
   }


   else {
      throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
            "Property referenced in indexed property path '" + tokens.canonicalName +
            "' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");
   }
}

通过对上面注入依赖代码的分析,我们已经明白了 Spring IOC 容器是如何将属性的值注入到 Bean 实例对象中去的:

  1. 对于集合类型的属性,将其属性值解析为目标类型的集合后直接赋值给属性。
  2. 对于非集合类型的属性,大量使用了 JDK
    的反射机制,通过属性的 getter()方法获取指定属性注入以前的值,同时调用属性的 setter()方法为属性设置注入后的值。看到这里相信很多人都明白了 Spring的 setter()注入原理。

在这里插入图片描述

至此 Spring IOC 容器对 Bean 定义资源文件的定位,载入、解析和依赖注入已经全部分析完毕,现在Spring IOC 容器中管理了一系列靠依赖关系联系起来的 Bean,程序不需要应用自己手动创建所需的对象,Spring IOC 容器会在我们使用的时候自动为我们创建,并且为我们注入好相关的依赖,这就是Spring 核心功能的控制反转和依赖注入的相关功能。

文章转自

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值