SpringIOC容器初始化过程总结

最近学习了SpringIOC的源码。将自己的学习成果总结如下。

SpringIOC

IOC容器:所有上层框架bean实例依赖环境

BeanFactory简介

BeanFactory : bean工厂提供bean的实例

beanFactory在早期设计中就只是一个提供bean实例对象工厂,通过各种条件定位到我们所需要的Bean,作为顶层接口定义了IOC容器的基本规范。

我们可以看一下BeanFactory这个接口中声明的属性及方法

  • String FACTORY_BEAN_PREFIX = “&”;

    这是BeanFactory接口中的唯一一个属性。这个地方需要衍生出一个概念,Spring 中有两种类型的bean。一种是普通的JavaBean,另一种是工厂bean(FactoryBean,需要实现Spring定义的FactoryBean接口),这两种bean都由SpringIOC容器来进行管理。FactoryBean和javaBean不同的地方在于通过BeanFactory类的getBean方法直接获取到的并不是FactoryBean的实例而是 FactoryBean中的方法getObject返回的对象。假如我们需要获取FactoryBean的实例。我们需要在getBean方法获取实例的时候在参数前加入"&"符号就行了。即BeanFactory中的FACTORY_BEAN_PREFIX属性。

  • Object getBean(String name) throws BeansException;

    通过名称获取bean实例,之后会详细讲解这个方法

  • T getBean(String name, Class requiredType) throws BeansException;

    通过注释 Behaves the same as {@link #getBean(String)}, but provides a measure of type 我们可以看出来这个方法行为和getBean(String name)相同,但是提供了类型的度量。不同于上面的getBean方法的是。如果我们获取到的bean和传入的类型不一致,则会抛出BeanNotOfRequiredTypeException异常。

  • T getBean(Class requiredType) throws BeansException;

    返回与所需类型匹配的单个bean的实例

  • Object getBean(String name, Object… args) throws BeansException;

    args参数,用于使用显式参数创建bean实例
    *(仅在创建新实例而不是检索现有实例时应用)

  • T getBean(Class requiredType, Object… args) throws BeansException;

    同理获取给定类型的bean,args参数在创建实例时使用

  • boolean containsBean(String name);

    是否包含该bean

  • boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    这个bean是否是单例

  • boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    是否getBean方法每次都返回不同的实例

  • boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

    检查具有给定名称的bean是否与指定类型匹配。这里插一点内容。ResolvableType是Spring4.0之后推出的一个类。不同于下面这个方法的是。Class是一种类型,但它本身不具有类型的属性。ResolvableType为所有的java类型提供了统一的数据结构以及API,换句话说,一个ResolvableType对象就对应着一种java类型。我们可以通过ResolvableType对象获取类型携带的信息。例如父类型,接口类型,Type对象到class对象的转换等。在Spring框架中需要反射的时候,为了不丢失信息,通常使用ResolvableType来进行封装类型。

  • boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    检查具有给定名称的bean是否与指定类型匹配。

  • Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    获取具有给定名称的bean的类型。

  • String[] getAliases(String name);

    返回别名,如果没有则返回空数组。在getBean方法中,所有的别名都指向同一个Bean。如果传入的参数是别名,则同时返回原始Bean的名称,并且Bean的名称作为数组中的第一个元素。

逐步演进发展成这样:

我们再分别分析BeanFactory的子接口。

ListableBeanFactory

这个接口声明了一些获取多个Bean的方法。在BeanFactory中,getBean方法获取的都是单个Bean。大致看一下ListableBeanFactory中声明的方法

通过方法名我们可以很清晰的看到每个方法的作用,这里引入了一个新的名称:BeanDefinition。

BeanDefinition

BeanDefinition接口继承了AttributeAccessor,BeanMetadataElement接口。

AttributeAccessor接口定义了最基本的对任意对象的元数据的修改或者获取。基本接口如下:

BeanMetadataElement 接口提供了一个getResource()方法,用来传输一个可配置的源对象。getResource方法返回此元数据元素的配置源对象。

看完两个接口以后,我们再来看BeanDefinition的声明

一个BeanDefinition描述了一个bean的实例,包括属性值,构造方法参数值和继承自它的类的更多信息。BeanDefinition仅仅是一个最简单的接口,主要功能是允许BeanFactoryPostProcessor例如PropertyPlaceHolderConfigure能够检索并修改属性值和别的bean的元数据。BeanDefinition就是Spring中的Bean,我们定义的Bean会转化成为一个个BeanDefinition存在于Spring的BeanFactory当中。注意几个比较重要的点:

  • setAutowireCandidate方法

    设置该bean是否可以注入到其他的Bean当中。只对根据类型注入有效。如果根据名称注入,即使这里设置的为false。也可以注入成功。

  • setPrimary 方法

    当同一个接口有多个实现的时候,Spring会优先选择设置primary为true的bean

  • BeanFactoryPostProcessor

    对已经加载好的BeanDefinition进行处理。SpringIOC容许BeanFactoryPostProcessor在容器实际实例化任何bean之前读取配置的元数据。例如我们常用的${property}这样的表达式,实际上就是对配置信息进行替换。这样使得配置解耦。具体的实现逻辑就是在BeanFactoryPostProcessor相关的实现类中的postProcessBeanFactory方法中实现的。

  • methodOverrides

    方法重写的持有者,记录lookup-method,replaced-method元素。

HierarchicalBeanFactory

接下来继续看HierarchicalBeanFactory接口,实现该接口的BeanFactory具有继承关系。

AutowireCapableBeanFactory接口,实现该接口的BeanFactory可以自动装配bean。

BeanFactory的默认实现类DefaultListableBeanFactory。随着Spring的扩展,DefaultListableBeanFactory无法满足各种各样的情况下Bean的获取及生产。然后又逐步演进出了ApllicationContext。SpringIOC的过程中,本质上是ApplicationContext持有了一个DefaultListableBeanFactory。这个类很重要,他同时实现了BeanDefinitionRegistry接口。BeanDefinitionRegistry接口的主要作用是向注册表中注册BeanDefinition实例。完成注册的过程。

DefaultListableBeanFactory

DefaultListableBeanFactory是BeanFactory的默认实现类,实现了BeanFactory下层的三个接口。

ApllicationContext

ApllicationContext的架构图如下所示:

IOC容器初始化过程

资源加载 -> 资源解析 -> BeanDefinition注册 -> getBean()获取bean的实例

ContextLoaderListener

传统的Spring项目中,我们需要在web.xml文件中配置如下内容:

org.springframework.web.context.ContextLoaderListener

ContextLoaderListener 继承自ContextLoader,实现了ServletContextListener接口。

这里是可以看作是我们Spring在web开发过程中的起点,ContextLoaderListener可以指定在web应用程序启动时载入IOC容器,正是通过ContextLoader来实现的。ContextLoader来完成实际的WebApplicationContext也就是IOC容器的初始化工作。ServletContextListener接口里的函数会结合Web容器的生命周期被调用。因为ServletContextListener是ServletContext的监听者,如果ServletContext发生变化,会触发相应的事件,而监听器一直对事件监听,如果接受到了变化,就会做出预先设计好的相应动作,由于ServletContext变化而触发的监听器的响应有服务器启动时,servletContext被创建,服务器关闭时,servletContext被销毁。所以contextLoaderListener的作用是启动web容器时,读取在contextConfigLocation中定义的xml文件,自动装配ApplicationContext的配置信息,并产生WebApplicationContext对象。然后将这个对象放置在ServletContext的属性里。这样我们可以通过servlet获取到WebApplicationContext对象,并利用这个对象访问Spring容器管理的bean。

同样我们还需要在web.xml中配置context-param参数。

contextConfigLocation /WEB-INF/ * -servlet.xml,classpath:conf/applicationContext- * .xml

在ContextLoader的加载过程中,会读取contextConfigLocation参数的值,然后解析资源配置文件。

代码调用链

接下来我们启动一个Spring配置的项目,来一步一步的解析IOC容器的初始化过程。

contextInitialized

首先代码的入口在ContextLoaderListener的contextInitialized方法中,ServletContext创建时会调用该方法。

@Override
public void contextInitialized(ServletContextEvent event) {
   initWebApplicationContext(event.getServletContext());
}

我们可以看到这个方法实际上是调用了contextLoader类里面的initWebApplicationContext方法。接下来我们点进initWebApplicationContext方法中。

initWebApplicationContext

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
   if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
      throw new IllegalStateException(
            "Cannot initialize context because there is already a root application context present - " +
            "check whether you have multiple ContextLoader* definitions in your web.xml!");
   }

   Log logger = LogFactory.getLog(ContextLoader.class);
   servletContext.log("Initializing Spring root WebApplicationContext");
   if (logger.isInfoEnabled()) {
      logger.info("Root WebApplicationContext: initialization started");
   }
   long startTime = System.currentTimeMillis();

   try {
      // Store context in local instance variable, to guarantee that
      // it is available on ServletContext shutdown.
      if (this.context == null) {
         this.context = createWebApplicationContext(servletContext);
      }
      if (this.context instanceof ConfigurableWebApplicationContext) {
         ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
         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 ->
               // determine parent for root web application context, if any.
               ApplicationContext parent = loadParentContext(servletContext);
               cwac.setParent(parent);
            }
            configureAndRefreshWebApplicationContext(cwac, servletContext);
         }
      }
      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

      ClassLoader ccl = Thread.currentThread().getContextClassLoader();
      if (ccl == ContextLoader.class.getClassLoader()) {
         currentContext = this.context;
      }
      else if (ccl != null) {
         currentContextPerThread.put(ccl, this.context);
      }

      if (logger.isDebugEnabled()) {
         logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
               WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
      }
      if (logger.isInfoEnabled()) {
         long elapsedTime = System.currentTimeMillis() - startTime;
         logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
      }

      return this.context;
   }
   catch (RuntimeException ex) {
      logger.error("Context initialization failed", ex);
      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
      throw ex;
   }
   catch (Error err) {
      logger.error("Context initialization failed", err);
      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
      throw err;
   }
}

这个方法里面有几个比较重要的方法。首先在ServletContext中找有没有ApplicationContext存在,如果有则报错,因为ServletContext只会初始化一次,ApplicationContext也只会创建一次。接下来我们看createWebApplication(servlet)方法

createWebApplication

在createWebApplication方法中,首先通过datermineContextClass(sc)来确定实现类,如果在web.xml中配置了contextClass参数,值为webApplicationContext的实现类,则返回配置类的Class。如果没有配置,则会返回Spring默认的实现类XmlWebApplicationContext。然后生成一个ApplicationContext的对象。

回到initWebApplicaitonContext方法中,因为XmlWebApplicationContext间接实现了ConfigurableWebApplicationContext接口,所以将会执行configureAndRefreshWebApplicationContext(cwac, servletContext);方法。

configureAndRefreshWebApplicationContext
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
   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
      String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
      if (idParam != null) {
         wac.setId(idParam);
      }
      else {
         // Generate default id...
         wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
               ObjectUtils.getDisplayString(sc.getContextPath()));
      }
   }

   wac.setServletContext(sc);
   String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
   if (configLocationParam != null) {
      wac.setConfigLocation(configLocationParam);
   }

   // 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(sc, null);
   }

   customizeContext(sc, wac);
   wac.refresh();
}

这个方法我们可以看到会读取我们前面配置在web.xml文件当中的contextConfigLocation参数,如果没有配置,默认读取路径为 “/WEB-INF/applicationContext.xml”。这个方法里面有一个最重要的方法,refresh();这个方法才是真正的Spring配置工作,具体实现在AbstractApplicationContext当中。接下来会具体讲这个方法。

refresh

这个方法是SpringIOC容器初始化的核心,需要一个一个的讲解,先大概看一下具有以下的方法。

public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // 初始化准备工作
      prepareRefresh();

      // 获取BeanFactory
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // BeanFactory的预准备工作
      prepareBeanFactory(beanFactory);

      try {
         // beanFactory准备工作完成之后进行的后置处理工作。
         postProcessBeanFactory(beanFactory);

         // 调用BeanFactoryPostProcessor各个实现类的postProcessFactory(factory)方法。
         invokeBeanFactoryPostProcessors(beanFactory);

         // 注册BeanPostProcessor的实现类
         registerBeanPostProcessors(beanFactory);

         // 初始化当前ApplicationContext的MessageSource
         initMessageSource();

         //初始化ApplicationContext事件广播器
         initApplicationEventMulticaster();

         // 钩子方法,在这里可以初始化一些特殊的bean
         onRefresh();

         // 注册事件监听器
         registerListeners();

         // 初始化所有的singleton beans
         finishBeanFactoryInitialization(beanFactory);

         //广播初始化完成
         finishRefresh();
      }

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

         // Destroy already created singletons to avoid dangling resources.
         destroyBeans();

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

         // Propagate exception to caller.
         throw ex;
      }

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

准备工作,记录下容器的启动时间,标记为已启动状态,处理配置文件中的占位符。

protected void prepareRefresh() {
   this.startupDate = System.currentTimeMillis();
   this.closed.set(false);
   this.active.set(true);

   if (logger.isInfoEnabled()) {
      logger.info("Refreshing " + this);
   }

   // Initialize any placeholder property sources in the context environment
   initPropertySources();

   // Validate that all properties marked as required are resolvable
   // see ConfigurablePropertyResolver#setRequiredProperties
   getEnvironment().validateRequiredProperties();

   // Allow for the collection of early ApplicationEvents,
   // to be published once the multicaster is available...
   this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
obtainFreshBeanFactory

将配置文件解析为bean的定义,注册到BeanFactory中。bean还没有完全初始化,但是具有了一个beanName->beanDefinition的map

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   refreshBeanFactory();
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (logger.isDebugEnabled()) {
      logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
   }
   return beanFactory;
}
refreshBeanFactory

实现类位于AbstractRefreshableApplicationContext

@Override
protected final void refreshBeanFactory() throws BeansException {
	//如果ApplicationContext中已经加载过了BeanFactory,销毁所有的Bean并关闭BeanFactory。
	//这里需要知道,应用中的BeanFactory可以是多个的,检查的是当前ApplicationContext是否有BeanFactory
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
  		// 初始化一个DefaultListableBeanFactory。
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      // 将BeanFactory进行序列话
      beanFactory.setSerializationId(getId());
      // 设置BeanFactory的两个属性,是否允许Bean覆盖,是否允许循环引用。
      customizeBeanFactory(beanFactory);
      // 加载Bean到BeanFactory中
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
         this.beanFactory = beanFactory;
      }
   }
   catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
   }
}

通过观察hasBeanFactory方法我们可以知道,这里检查的是当前对象的属性beanFactory是否被初始化了。所以ApplicationContext继承自BeanFactory,但本质上是持有了一个DefaultListableBeanFactory的对象。

  • customizeBeanFactory

    protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
    	// 是否允许Bean的定义覆盖
       if (this.allowBeanDefinitionOverriding != null) {
          beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
       }
       	// 是否允许Bean循环依赖
       if (this.allowCircularReferences != null) {
          beanFactory.setAllowCircularReferences(this.allowCircularReferences);
       }
    }
    

    默认情况下,Spring允许循环依赖。之后会讲解Spring如何解决循环依赖的问题。

  • loadBeanDefinitions

    实现类在XmlWebApplicationContext中

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
       // Create a new XmlBeanDefinitionReader for the given BeanFactory. 
       XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    
       // Configure the bean definition reader with this context's
       // resource loading environment.
       beanDefinitionReader.setEnvironment(this.getEnvironment());
       beanDefinitionReader.setResourceLoader(this);
       beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    
       // Allow a subclass to provide custom initialization of the reader,
       // then proceed with actually loading the bean definitions.
       initBeanDefinitionReader(beanDefinitionReader);
       loadBeanDefinitions(beanDefinitionReader);
    }
    

    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); 这一步构造了一个XmlBeanDefinitionReader实例。我们可以看到的是传入了一个BeanDefinitionRegistry的实现对象beanFactory。在之后的解析过程中,我们所使用的registry就是用的beanFactory。

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
       String[] configLocations = getConfigLocations();
       if (configLocations != null) {
          for (String configLocation : configLocations) {
             reader.loadBeanDefinitions(configLocation);
          }
       }
    }
    

    这个地方的configLocations实质上就是我们前面在web.xml里面配置的contextConfigLocation参数。

    接下来我们来看reader.loadBeanDefinitions(configLocation);这个方法。这个方法的实现位于XmlBeanDefinitionReader的父类AbstractBeanDefinitionReader中。经过简单的调用之后,执行以下代码:

    public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
    //之前新建对象时会初始化一个ResourceLoader,这里返回ResourceLoader。
       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 {
          //获取资源,这里返回的就是一个我们配置的xml文件的资源。
             Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
             int loadCount = loadBeanDefinitions(resources);
             if (actualResources != null) {
                for (Resource resource : resources) {
                   actualResources.add(resource);
                }
             }
             if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
             }
             return loadCount;
          }
          catch (IOException ex) {
             throw new BeanDefinitionStoreException(
                   "Could not resolve bean definition resource pattern [" + location + "]", ex);
          }
       }
       else {
          // Can only load single resources by absolute URL.
          Resource resource = resourceLoader.getResource(location);
          int loadCount = loadBeanDefinitions(resource);
          if (actualResources != null) {
             actualResources.add(resource);
          }
          if (logger.isDebugEnabled()) {
             logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
          }
          return loadCount;
       }
    }
    

    我们来看这一步int loadCount = loadBeanDefinitions(resources); 这里经过简单的调用之后会进入XmlBeanDefinitionReader的loadBeanDefinitions方法。如下:

    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
       Assert.notNull(encodedResource, "EncodedResource must not be null");
       if (logger.isInfoEnabled()) {
          logger.info("Loading XML bean definitions from " + encodedResource.getResource());
       }
    	//这里获取资源,第一次进来的时候为null
       Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
       if (currentResources == null) {
       //初始化并赋值给resourcesCurrentlyBeingLoaded
          currentResources = new HashSet<EncodedResource>(4);
          this.resourcesCurrentlyBeingLoaded.set(currentResources);
       }
       if (!currentResources.add(encodedResource)) {
          throw new BeanDefinitionStoreException(
                "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
       }
       try {
          InputStream inputStream = encodedResource.getResource().getInputStream();
          try {
             InputSource inputSource = new InputSource(inputStream);
             if (encodedResource.getEncoding() != null) {
                inputSource.setEncoding(encodedResource.getEncoding());
             }
             return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
          }
          finally {
             inputStream.close();
          }
       }
       catch (IOException ex) {
          throw new BeanDefinitionStoreException(
                "IOException parsing XML document from " + encodedResource.getResource(), ex);
       }
       finally {
          currentResources.remove(encodedResource);
          if (currentResources.isEmpty()) {
             this.resourcesCurrentlyBeingLoaded.remove();
          }
       }
    }
    

这个方法就是简单的获取文件流然后调用doLoadBeanDefinitions方法。接下来我们来看一下doLoadBeanDefinitions方法。这个方法依旧在XmlBeanDefinitionReader中

主要只有两行代码

// 将资源文件解析为Document
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);

接下来我们看registerBeanDefinitions。

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	 //使用DefaultBeanDefinitionDocumentReader实例化BeanDefinitionDocumentReader
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
   // 记录统计前BeanDefintion的加载个数
   int countBefore = getRegistry().getBeanDefinitionCount();
   // 加载及注册bean
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   // 记录本次加载的BeanDefintion个数
   return getRegistry().getBeanDefinitionCount() - countBefore;
}

这里调用了documentReader的registerBeanDefinitions方法。实现类为DefaultBeanDefinitionDocumentReader

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

走到这一步的时候,资源文件已经变成了一个Element,接下来就是解析这个Element并注册了。

protected void doRegisterBeanDefinitions(Element root) {
  // BeanDefinitionParserDelegate 用于解析XML bean定义的有状态委托类。
   BeanDefinitionParserDelegate parent = this.delegate;
   this.delegate = createDelegate(getReaderContext(), root, parent);

   if (this.delegate.isDefaultNamespace(root)) {
   //这里是解析配置了profile属性的beans
      String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
      if (StringUtils.hasText(profileSpec)) {
         String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
               profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
         if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
            return;
         }
      }
   }

   preProcessXml(root);
   parseBeanDefinitions(root, this.delegate);
   postProcessXml(root);

   this.delegate = parent;
}
  • BeanDefinitionParserDelegate类提供了解析spring配置文件功能,对于默认空间下的元素()在该类内部实现,对于其它命名空间下的元素可以通过绑定NamespaceHandler的方式来实现,针对每个命名空间下的元素提供不同BeanDefinitionParser来实现.
  • preProcessXml和postProcessXml都是空的。钩子方法。一个类要么是面向继承设计,要么就用final修饰。
  • 判断是否为默认的命名空间 。即root的namespaceURI是否为http://www.springframework.org/schema/beans
  • 假如我们配置了Spring.profiles.active属性,则会对beans标签进行解析,是否是当前环境所需要的bean
  • 重点讲解DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法。

parseBeanDefinitions

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
   if (delegate.isDefaultNamespace(root)) {
      NodeList nl = root.getChildNodes();
      for (int i = 0; i < nl.getLength(); i++) {
         Node node = nl.item(i);
         if (node instanceof Element) {
            Element ele = (Element) node;
            if (delegate.isDefaultNamespace(ele)) {
               parseDefaultElement(ele, delegate);
            }
            else {
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}

这里我们可以看到所有的解析方法都进入了parseDefaultElement(ele, delegate);和 delegate.parseCustomElement(ele);parseDefaultElement方法解析的是,,,

这四个标签之所以是默认标签,是因为他们处于http://www.springframework.org/schema/beans这个namespace下定义的。

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
   if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
      importBeanDefinitionResource(ele);
   }
   else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
      processAliasRegistration(ele);
   }
   else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
      processBeanDefinition(ele, delegate);
   }
   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      // recurse
      doRegisterBeanDefinitions(ele);
   }
}

其他的标签类似于,,,等都会进入parseCustomElement这个方法。

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
   String namespaceUri = getNamespaceURI(ele);
   NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
   if (handler == null) {
      error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
      return null;
   }
   return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
processBeanDefinition

不同的标签会有不同的NamespaceHandler来进行解析。我们看一下bean标签是如何被解析的

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//将<bean/>标签节点的信息提取出来,然后封装到一个BeanDefintionHolder中。包含了配置文件中配置的各种属性了。
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // Register the final decorated instance.
         BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      catch (BeanDefinitionStoreException ex) {
         getReaderContext().error("Failed to register bean definition with name '" +
               bdHolder.getBeanName() + "'", ele, ex);
      }
      // Send registration event.
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}

我们来跟进如何解析BeanDefinition的。首先从元素的解析及信息提取开始。也就是 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);方法。我们进入BeanDefinitionDelegate类的parseBeanDefinitionElement方法。如下:

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
//解析id属性
   String id = ele.getAttribute(ID_ATTRIBUTE);
   //解析name属性
   String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

//分割name属性
   List<String> aliases = new ArrayList<String>();
   if (StringUtils.hasLength(nameAttr)) {
      String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
      aliases.addAll(Arrays.asList(nameArr));
   }

   String beanName = id;
   //如果没有指定id,则设置别名列表的第一个名字作为beanN啊,e
   if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
      beanName = aliases.remove(0);
      if (logger.isDebugEnabled()) {
         logger.debug("No XML 'id' specified - using '" + beanName +
               "' as bean name and " + aliases + " as aliases");
      }
   }

   if (containingBean == null) {
      checkNameUniqueness(beanName, aliases, ele);
   }

//根据bean标签的配置创建Beandefinition。
   AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
   if (beanDefinition != null) {
   //如果不存在beanName,则根据Spring中提供的命名规则为当前bean生成对应的beanName
      if (!StringUtils.hasText(beanName)) {
         try {
            if (containingBean != null) {
               beanName = BeanDefinitionReaderUtils.generateBeanName(
                     beanDefinition, this.readerContext.getRegistry(), true);
            }
            else {
               beanName = this.readerContext.generateBeanName(beanDefinition);
               // Register an alias for the plain bean class name, if still possible,
               // if the generator returned the class name plus a suffix.
               // This is expected for Spring 1.2/2.0 backwards compatibility.
               String beanClassName = beanDefinition.getBeanClassName();
               if (beanClassName != null &&
                     beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                     !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                  aliases.add(beanClassName);
               }
            }
            if (logger.isDebugEnabled()) {
               logger.debug("Neither XML 'id' nor 'name' specified - " +
                     "using generated bean name [" + beanName + "]");
            }
         }
         catch (Exception ex) {
            error(ex.getMessage(), ele);
            return null;
         }
      }
      String[] aliasesArray = StringUtils.toStringArray(aliases);
      return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
   }

   return null;
}

这个方法主要做了以下几步

  • 提取元素的id和name属性

  • 进一步解析其他所有的属性并统一封装到AbstractBeanDefinition类型的实例中

  • 如果检测到bean没有制定beanName,那么使用默认规则为此bean生成beanName

  • 将获取到的信息封装到BeanDefinitionHolder的实例中。

    看一下如何封装到AbstractBeanDefinition当中的。

    public AbstractBeanDefinition parseBeanDefinitionElement(
          Element ele, String beanName, BeanDefinition containingBean) {
    
       this.parseState.push(new BeanEntry(beanName));
    
       String className = null;
       //解析class属性
       if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
          className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
       }
    
       try {
          String parent = null;
          if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
             parent = ele.getAttribute(PARENT_ATTRIBUTE);
          }
          //创建BeanDefinition并设置类信息。
          AbstractBeanDefinition bd = createBeanDefinition(className, parent);
    
    			//解析bean的各种属性
          parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
          //设置description
          bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
    			//解析<meta/>	
          parseMetaElements(ele, bd);
          //解析<lookup-method/>	
          parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
           //解析<replaced-method/>	
          parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
    			//解析<constructor-arg/>	
          parseConstructorArgElements(ele, bd);
          //解析<property/>	
          parsePropertyElements(ele, bd);
          //解析<qualifier/>	
          parseQualifierElements(ele, bd);
    
          bd.setResource(this.readerContext.getResource());
          bd.setSource(extractSource(ele));
    
          return bd;
       }
       catch (ClassNotFoundException ex) {
          error("Bean class [" + className + "] not found", ele, ex);
       }
       catch (NoClassDefFoundError err) {
          error("Class that bean class [" + className + "] depends on not found", ele, err);
       }
       catch (Throwable ex) {
          error("Unexpected failure during bean definition parsing", ele, ex);
       }
       finally {
          this.parseState.pop();
       }
    
       return null;
    }
    

可以看到的是这个方法将标签都解析到AbstractBeanDefinition上了。

  • meta标签:meta标签并不会体现在bean的属性当中,而是需要的时候通过BeanDefinition的getAttribute获取。
  • lookup-method标签:Spring动态改变bean里方法的实现。方法执行返回的对象,使用Spring内原有的这类对象替换,通过改变方法返回值来动态改变方法,内部实现为使用cglib方法。重新生成子类,重写配置的方法和返回对象,达到动态改变的效果。这段话看起来有点抽象,我们通常称为获取器注入,我们在lookup-method标签里定义的name为方法名,bean为返回值对象。
  • replaced-method:方法替换,可以在运行时用新的方法替换现有的方法。与之前的look-up不同的是,replaced-method不但可以动态地替换返回实体bean,而且还能动态地更改原有方法的逻辑。

到这一步,我们已经根据一个bean标签完成了一个BeanDefinitionHolder实例的创建。我们看一下BeanDefinitionHolder里面的内容。

回到processBeanDefinition中,当我们完成processBeanDefintion后我们接下来会进行bean的注册

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

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

   // Register bean definition under primary name.
   String beanName = definitionHolder.getBeanName();
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

   // Register aliases for bean name, if any.如果还有别名,将别名也注册
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String alias : aliases) {
         registry.registerAlias(beanName, alias);
      }
   }
}

显而易见,这个方法里面最重要的就是 registry.registerBeanDefinition。结合我们上面的提到的registry就是DefaultListableBeanFactory。接下来我们看DefaultListableBeanFactory的注册方法registerBeanDefinition。

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {

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

   if (beanDefinition instanceof AbstractBeanDefinition) {
      try {
         ((AbstractBeanDefinition) beanDefinition).validate();
      }
      catch (BeanDefinitionValidationException ex) {
         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
               "Validation of bean definition failed", ex);
      }
   }

   BeanDefinition oldBeanDefinition;
	//beanDefinitionMap实质上就是DefaultListableBeanFactory持有的一个ConcurrentHashMap
   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.");
      }
    //getRole 获取bean的分类,
    ///Bean角色,
    // int ROLE_APPLICATION = 0;  //应用程序重要组成部分
    // int ROLE_SUPPORT = 1;  //做为大量配置的一部分(支持、扩展类)
    // int ROLE_INFRASTRUCTURE = 2;  //指内部工作的基础构造
      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 {
   //判断是否有bean已经开始初始化了
      if (hasBeanCreationStarted()) {
         // Cannot modify startup-time collection elements anymore (for stable iteration)
         synchronized (this.beanDefinitionMap) {
            this.beanDefinitionMap.put(beanName, beanDefinition);
            List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
            updatedDefinitions.addAll(this.beanDefinitionNames);
            updatedDefinitions.add(beanName);
            this.beanDefinitionNames = updatedDefinitions;
            if (this.manualSingletonNames.contains(beanName)) {
               Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
               updatedSingletons.remove(beanName);
               this.manualSingletonNames = updatedSingletons;
            }
         }
      }
      else {
         // Still in startup registration phase  将beanDefinition放入map当中
         this.beanDefinitionMap.put(beanName, beanDefinition);
         // 已经注册的beanName添加进去
         this.beanDefinitionNames.add(beanName);
         // 从需要手动注册的bean中删除
         this.manualSingletonNames.remove(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }

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

到这一步,bean的解析已经完成了。我们回到refresh方法中。

prepareBeanFactory

设置BeanFactory的类加载器,添加几个BeanPostProcessor(还未注册BeanPostProcessor),手动注册特殊的bean。

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   // Tell the internal bean factory to use the context's class loader etc.
   //为ApplicationContext设置类加载器。
   beanFactory.setBeanClassLoader(getClassLoader());
   //设置BeanExpressionResovler SpEL表达式的解析器
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
   // 
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

   // Configure the bean factory with context callbacks.
   //设置BeanPostProcessor
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
   // 自动装备时忽略以下几个类
   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

   // BeanFactory interface not registered as resolvable type in a plain factory.
   // MessageSource registered (and found for autowiring) as a bean.
   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
   beanFactory.registerResolvableDependency(ResourceLoader.class, this);
   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
   beanFactory.registerResolvableDependency(ApplicationContext.class, this);

   // Detect a LoadTimeWeaver and prepare for weaving, if found.
   if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      // Set a temporary ClassLoader for type matching.
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }

   // Register default environment beans.
   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
   }
}
  • 这里又新引入了一个概念BeanPostProcessor。BeanPostProcessor可以在Spring容器实例化bean之后,在执行bean的初始化方法前后,添加一些自己的处理逻辑。bean的初始化方法指的是实现了initializingBean接口的afterPropertiesSet方法。或者bean定义时通过init-methode设置的方法。而BeanFactoryPostProcessor我们在上文中有提到过,在spring容器加载了bean的定义文件之后,在bean实例化之前执行的,允许修改bean的属性,例如将scope从singleton改为prototype。

看完了xml是如何解析的之后,我们直接进入正题,bean是如何实例化及初始化的。我们想要获取一个bean通常通过BeanFactory的getBean方法来获取。finishBeanFactoryInitialization方法通过简单的链式调用之后,也会进入到getBean方法中。getBean调用了doGetBean方法。

doGetBean
protected <T> T doGetBean(
      final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
      throws BeansException {
	//获取beanName,这里需要注意两个点。一种是处理FactoryBean,一种是将别名转换为真实的beanName。
   final String beanName = transformedBeanName(name);
   Object bean;

   //检查缓存中或者实例工厂中是否有对应的实例。
   //因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,
   //Spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光
   //也就是将ObjectFactory加入到缓存中,一旦下个bean创建时候需要依赖上个bean则直接使用ObjectFactory
   Object sharedInstance = getSingleton(beanName);
   // 假如doGetBean方法传入了args参数,那么我们不再是获取bean了,而是重新创建bean
   if (sharedInstance != null && args == null) {
      if (logger.isDebugEnabled()) {
         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 + "'");
         }
      }
      // 这个地方大家看起来可能就会有疑问了,明明已经获取了sharedInstance,为什么还要获取bean。
      // 这里其实就是因为如果是普通的bean,那么就直接返回sharedInstance了,
      // 如果是FactoryBean,那么我们返回FactoryBean的getObject对象。除非传入了&符号,则返回当前对象等。
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

   else {
      // Fail if we're already creating this bean instance:
      // We're assumably within a circular reference.
      // 假如当前线程已经创建过此beanName的原型的bean。那么会抛异常。这种情况产生的可能性是因为循环依赖。
      // 原型模式的情况下,无法解决循环依赖,因为依赖之后会重新创建对象。A创建B,B创建A。
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }

      // Check if bean definition exists in this factory.
      BeanFactory parentBeanFactory = getParentBeanFactory();
      //如果beanDefinitionMap中没有这个bean并且父beanFactory存在。则尝试从父容器中获取。
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
         // Not found -> check parent.
         String nameToLookup = originalBeanName(name);
         if (args != null) {
            // Delegation to parent with explicit args.
            return (T) parentBeanFactory.getBean(nameToLookup, args);
         }
         else {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
         }
      }

      if (!typeCheckOnly) {
      //如果不是仅仅做类型检查,而是创建bean,则将当前的beanName传入到一个alreadyCreated的Set集合当中
      //进行记录
         markBeanAsCreated(beanName);
      }
		//	到这一步就表明已经需要创建bean了。
      try {
      //  将存储xml配置文件的GenericBeanDefinition转换为RootBeanDefinition。
      //  如果BeanName是子Bean,同时会合并父类的相关属性。
         final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);

         //先实例化依赖的所有的bean
         String[] dependsOn = mbd.getDependsOn();
         if (dependsOn != null) {
            for (String dependsOnBean : dependsOn) {
               if (isDependent(beanName, dependsOnBean)) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
               }
               // 缓存依赖调用
               registerDependentBean(dependsOnBean, beanName);
               getBean(dependsOnBean);
            }
         }

         // 实例化所依赖的bean之后就可以实例化mbd本身了。
         //	单例模式创建
         if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
               @Override
               public Object getObject() throws BeansException {
                  try {
                  // 创建bean
                     return createBean(beanName, mbd, args);
                  }
                  catch (BeansException ex) {
                     // Explicitly remove instance from singleton cache: It might have been put there
                     // eagerly by the creation process, to allow for circular reference resolution.
                     // Also remove any beans that received a temporary reference to the bean.
                     destroySingleton(beanName);
                     throw ex;
                  }
               }
            });
            // 这里等同于上面的方法,解决FactoryBean等问题。
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }

         else if (mbd.isPrototype()) {
            // It's a prototype -> create a new instance.
            Object prototypeInstance = null;
            try {
               beforePrototypeCreation(beanName);
               prototypeInstance = createBean(beanName, mbd, args);
            }
            finally {
               afterPrototypeCreation(beanName);
            }
            bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
         }
					// 如果不是singleton和prototype类型的bean,则需要使用自己指定的scope的委托类来实现初始化。
         else {
            String scopeName = mbd.getScope();
            final Scope scope = this.scopes.get(scopeName);
            if (scope == null) {
               throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
            }
            try {
               Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                  @Override
                  public Object getObject() throws BeansException {
                     beforePrototypeCreation(beanName);
                     try {
                        return createBean(beanName, mbd, args);
                     }
                     finally {
                        afterPrototypeCreation(beanName);
                     }
                  }
               });
               bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
            }
            catch (IllegalStateException ex) {
               throw new BeanCreationException(beanName,
                     "Scope '" + scopeName + "' is not active for the current thread; consider " +
                     "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                     ex);
            }
         }
      }
      catch (BeansException ex) {
         cleanupAfterBeanCreationFailure(beanName);
         throw ex;
      }
   }

   // Check if required type matches the type of the actual bean instance.
   if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
      try {
         return getTypeConverter().convertIfNecessary(bean, requiredType);
      }
      catch (TypeMismatchException ex) {
         if (logger.isDebugEnabled()) {
            logger.debug("Failed to convert bean '" + name + "' to required type [" +
                  ClassUtils.getQualifiedName(requiredType) + "]", ex);
         }
         throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
   }
   return (T) bean;
}
  • FactoryBean#getObject()代理了getBean()方法。

  • getSingleton() 这一步是尝试从缓存中获取单例bean

  • protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // singletonObjects concurrentHashMap 存储了BeanName和bean实例之间的关系。
       Object singletonObject = this.singletonObjects.get(beanName);
       if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
          synchronized (this.singletonObjects) {
          // 判断一下是否正在加载,正在加载则不处理。
          // earlySingletonObjects也是保存beanName和bean实例之间的关系,但不同的是bean被放入之后
          // 即使bean还在创建过程中,就可以通过getBean方法获取了,目的是为了检测循环引用。
             singletonObject = this.earlySingletonObjects.get(beanName);
             if (singletonObject == null && allowEarlyReference) {
             // singletonFactories 用来保存beanName和创建bean工厂之间的关系。
             // ObjectFactory只是一个普通的工厂接口,不同于FactoryBean。
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                   singletonObject = singletonFactory.getObject();
                   this.earlySingletonObjects.put(beanName, singletonObject);
                   this.singletonFactories.remove(beanName);
                }
             }
          }
       }
       return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }
    
  • getObjectForBeanInstance

    看完这个方法之后,我们来分析getObjectForBeanInstance;

    protected Object getObjectForBeanInstance(
          Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
    
       // 不属于FactoryBean或者beanName有&前缀  异常
       if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
          throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
       }
    
      //现在我们有了bean实例,它可能是一个普通的bean或FactoryBean。
    	//如果它是FactoryBean,我们将使用它来创建Bean实例,
    	//除非调用者实际上想要对工厂的引用。 
       if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
          return beanInstance;
       }
    
       Object object = null;
       if (mbd == null) {
       // 尝试从缓存中加载bean
          object = getCachedObjectForFactoryBean(beanName);
       }
       if (object == null) {
          // Return bean instance from factory.
     		 //  可以确定Object是FactoryBean,从FactoryBean中获取对象
          FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
          // Caches object obtained from FactoryBean if it is a singleton.
          if (mbd == null && containsBeanDefinition(beanName)) {
          // 将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition
          // 如果指定BeanName是子Bean的话同时会合并父类的相关属性。
             mbd = getMergedLocalBeanDefinition(beanName);
          }
          // 是否是用户定义的bean而不是应用程序本身定义的bean
          boolean synthetic = (mbd != null && mbd.isSynthetic());
          object = getObjectFromFactoryBean(factory, beanName, !synthetic);
       }
       return object;
    }
    

我们可以看到真正的获取对象方法在getObjectFromFactoryBean中,限于篇幅,我们就不点进去了,但这个方法中主要的代码就是从FactoryBean#getObject()及一些前置后置处理。回到doGetBean当中,我们发现没有实例化的单例对象会调用createBean方法。我们找到一个实现类AbstractAutowireCapableBeanFactory的createBean方法。

  • createBean
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
   if (logger.isDebugEnabled()) {
      logger.debug("Creating instance of bean '" + beanName + "'");
   }
   RootBeanDefinition mbdToUse = mbd;

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

   // Prepare method overrides.
   try {
   //。处理<lookup-method>和<replaced-method>标签的方法
      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.
      // 添加BeanPostProcessor的代理
      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);
   }
	// 将持有代理的mbdToUse传入进行bean对象的创建
   Object beanInstance = doCreateBean(beanName, mbdToUse, args);
   if (logger.isDebugEnabled()) {
      logger.debug("Finished creating instance of bean '" + beanName + "'");
   }
   return beanInstance;
}
  • doCreateBean

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
       // Instantiate the bean.
       BeanWrapper instanceWrapper = null;
       if (mbd.isSingleton()) {
          instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
       }
       if (instanceWrapper == null) {
       //instanceWrapper为null代表不是FactoryBean,则实例化bean
          instanceWrapper = createBeanInstance(beanName, mbd, args);
       }
       final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
       Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
    
       // Allow post-processors to modify the merged bean definition.
       synchronized (mbd.postProcessingLock) {
          if (!mbd.postProcessed) {
             applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
             mbd.postProcessed = true;
          }
       } 
       //  是否需要提前曝光。
       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");
          }
          //。为了避免后期循环依赖,可以在bean初始化完成前,将创建实例的ObjectFactory加入工厂。
          addSingletonFactory(beanName, new ObjectFactory<Object>() {
             @Override
             public Object getObject() throws BeansException {
                return getEarlyBeanReference(beanName, mbd, bean);
             }
          });
       }
    
       // Initialize the bean instance.
       Object exposedObject = bean;
       try {
       // 对bean进行填充,将各个属性赋值。如果有循环依赖则递归初始化依赖bean。
          populateBean(beanName, mbd, instanceWrapper);
          if (exposedObject != null) {
          // 调用初始化方法,init-method方法。以及BeanPostProcessor的回调
             exposedObject = initializeBean(beanName, exposedObject, mbd);
          }
       }
       catch (Throwable ex) {
          if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
             throw (BeanCreationException) ex;
          }
          else {
             throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
          }
       }
    
       if (earlySingletonExposure) {
          Object earlySingletonReference = getSingleton(beanName, false);
          if (earlySingletonReference != null) {
             if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
             }
             else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                String[] dependentBeans = getDependentBeans(beanName);
                Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
                for (String dependentBean : dependentBeans) {
                   if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                      actualDependentBeans.add(dependentBean);
                   }
                }
                if (!actualDependentBeans.isEmpty()) {
                   throw new BeanCurrentlyInCreationException(beanName,
                         "Bean with name '" + beanName + "' has been injected into other beans [" +
                         StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                         "] in its raw version as part of a circular reference, but has eventually been " +
                         "wrapped. This means that said other beans do not use the final version of the " +
                         "bean. This is often the result of over-eager type matching - consider using " +
                         "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                }
             }
          }
       }
    
       // Register bean as disposable.
       try {
          registerDisposableBeanIfNecessary(beanName, bean, mbd);
       }
       catch (BeanDefinitionValidationException ex) {
          throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
       }
    
       return exposedObject;
    }
    

    这个方法中比较重要的三步

    • createBeanInstance 实例化bean,将BeanDefinition转化为BeanWrapper。
    • populateBean 属性赋值
    • initializeBean 毁掉方法
createBeanInstance
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
   // 解析class
   Class<?> beanClass = resolveBeanClass(mbd, beanName);

   if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
      throw new BeanCreationException(mbd.getResourceDescription(), beanName,
            "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
   }
	// 如果工厂方法部位空则使用工厂方法初始化策略
   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) {
      // 处理构造函数依赖注入
         return autowireConstructor(beanName, mbd, null, null);
      }
      else {
      // 无参构造函数
         return instantiateBean(beanName, mbd);
      }
   }

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

   //调用无参构造函数
   return instantiateBean(beanName, mbd);
}
  • 无参构造函数instantiateBean -> getInstantitionStrategy().instantiate()

  • 下面我们看一下实例化策略

    public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
       // Don't override the class with CGLIB if no overrides.
       // 如果不存在方法覆载,则直接使用反射生成对象
       if (bd.getMethodOverrides().isEmpty()) {
          Constructor<?> constructorToUse;
          synchronized (bd.constructorArgumentLock) {
             constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
             if (constructorToUse == null) {
                final Class<?> clazz = bd.getBeanClass();
                if (clazz.isInterface()) {
                   throw new BeanInstantiationException(clazz, "Specified class is an interface");
                }
                try {
                   if (System.getSecurityManager() != null) {
                      constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
                         @Override
                         public Constructor<?> run() throws Exception {
                            return clazz.getDeclaredConstructor((Class[]) null);
                         }
                      });
                   }
                   else {
                      constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
                   }
                   bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                }
                catch (Exception ex) {
                   throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }
             }
          }
          return BeanUtils.instantiateClass(constructorToUse);
       }
       else {
          //存在方法覆写,则需要使用cglib
          return instantiateWithMethodInjection(bd, beanName, owner);
       }
    }
    
  • populateBean

    protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
       PropertyValues pvs = mbd.getPropertyValues();
    
       if (bw == null) {
          if (!pvs.isEmpty()) {
             throw new BeanCreationException(
                   mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
          }
          else {
             // Skip property population phase for null instance.
             return;
          }
       }
    
     	// bean的实例化已经完成,但是还未给属性复制
     	// InstantiationAwareBeanPostProcessor可以对bean进行状态的修改
       boolean continueWithPropertyPopulation = true;
    
       if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
          for (BeanPostProcessor bp : getBeanPostProcessors()) {
             if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                   continueWithPropertyPopulation = false;
                   break;
                }
             }
          }
       }
    
       if (!continueWithPropertyPopulation) {
          return;
       }
    
       if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
             mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
          MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
    
    
          // 根据名称注入属性
          // newPvs中存储了一个propertyValueList,
          // list里面装有属性PropertyValue,含有属性的名称和值等属性
          if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
             autowireByName(beanName, mbd, bw, newPvs);
          }
    
          // 根据类型注入属性
          if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
             autowireByType(beanName, mbd, bw, newPvs);
          }
    
          pvs = newPvs;
       }
    
       boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
       boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
    
       if (hasInstAwareBpps || needsDepCheck) {
          PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
          if (hasInstAwareBpps) {
             for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                   InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                   pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                   if (pvs == null) {
                      return;
                   }
                }
             }
          }
          if (needsDepCheck) {
             checkDependencies(beanName, mbd, filteredPds, pvs);
          }
       }
    	// 将属性应用到bean中
       applyPropertyValues(beanName, mbd, bw, pvs);
    }
    
    • InstantiationAwareBeanPostProcessor接口继承BeanPostProcessor接口,它内部提供了3个方法,再加上BeanPostProcessor接口内部的2个方法,所以实现这个接口需要实现5个方法。

      // postProcessBeforeInstantiation方法的作用在目标对象被实例化之前调用的方法,可以返回目标实例的一个代理用来代替目标实例
      // beanClass参数表示目标对象的类型,beanName是目标实例在Spring容器中的name
      // 返回值类型是Object,如果返回的是非null对象,接下来除了postProcessAfterInitialization方法会被执行以外,其它bean构造的那些方法都不再执行。否则那些过程以及postProcessAfterInitialization方法都会执行
      Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;

      // postProcessAfterInstantiation方法的作用在目标对象被实例化之后并且在属性值被populate之前调用
      // bean参数是目标实例(这个时候目标对象已经被实例化但是该实例的属性还没有被设置),beanName是目标实例在Spring容器中的name
      // 返回值是boolean类型,如果返回true,目标实例内部的返回值会被populate,否则populate这个过程会被忽视
      boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;

      // postProcessPropertyValues方法的作用在属性中被设置到目标实例之前调用,可以修改属性的设置
      // pvs参数表示参数属性值(从BeanDefinition中获取),pds代表参数的描述信息(比如参数名,类型等描述信息),bean参数是目标实例,beanName是目标实例在Spring容器中的name
      // 返回值是PropertyValues,可以使用一个全新的PropertyValues代替原先的PropertyValues用来覆盖属性设置或者直接在参数pvs上修改。如果返回值是null,那么会忽略属性设置这个过程(所有属性不论使用什么注解,最后都是null)
      PropertyValues postProcessPropertyValues(
      PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
      throws BeansException;

      InstantiationAwareBeanPostProcessor接口的主要作用在于目标对象的实例化过程中需要处理的事情,包括实例化对象的前后过程以及实例的属性设置
      postProcessBeforeInstantiation方法是最先执行的方法,它在目标对象实例化之前调用,该方法的返回值类型是Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(比如代理对象)。如果该方法的返回值代替原本该生成的目标对象,后续只有postProcessAfterInitialization方法会调用,其它方法不再调用;否则按照正常的流程走
      postProcessAfterInstantiation方法在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。如果该方法返回false,会忽略属性值的设置;如果返回true,会按照正常流程设置属性值
      postProcessPropertyValues方法对属性值进行修改(这个时候属性值还未被设置,但是我们可以修改原本该设置进去的属性值)。如果postProcessAfterInstantiation方法返回false,该方法不会被调用。可以在该方法内对属性值进行修改
      父接口BeanPostProcessor的2个方法postProcessBeforeInitialization和postProcessAfterInitialization都是在目标对象被实例化之后,并且属性也被设置之后调用的
      Instantiation表示实例化,Initialization表示初始化。实例化的意思在对象还未生成,初始化的意思在对象已经生成

到这一步实例化和属性赋值都已经完成了,接下来就进行初始化操作

initializeBean
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
   if (System.getSecurityManager() != null) {
      AccessController.doPrivileged(new PrivilegedAction<Object>() {
         @Override
         public Object run() {
            invokeAwareMethods(beanName, bean);
            return null;
         }
      }, getAccessControlContext());
   }
   else {
   // 如果bean实现了一些Aware接口,则进行回调。
   // 实现Aware接口的bean会被注入相应实例。
   // 例如我们项目开发过程中常用的ApplicationContextAware接口来获取ApplicationContext
      invokeAwareMethods(beanName, bean);
   }

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

   try {
   // 调用用户自定义的init方法
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }

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

走到这一步,我们就知道了BeanPostProcessor接口到底在哪里进行回调了。实例化及属性赋值完成之后对初始化的对象进行前后回调了。

总结

限于篇幅,有些地方的代码可能还不够深入,但SpringIOC容器初始化的过程就大致如上所示了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章