[Spring基本功系列]Spring源碼之IOC原理

前言

常見的概念就不一一介紹(例如一些什麼注入方式,官方文檔裏面都是有的,文檔最後會給出連接的),這裏咱們抓主幹,上帝視角把這IOC原理簡單的摸摸清html

基本概念

經過官方的一張高層視圖,很容易理解:經過配置(註解/xml形式)容器幫咱們負責建立對象,咱們只須要負責get,而後作就好了;至關於說容器作了一層解耦:剝離了對象實例的建立銷燬過程和調用的過程,調用者只須要關心對象自己就好了,容器會幫咱們管理好對象的存亡java

容器高層原理圖
容器高層原理圖
image-20191231104332673
image-20191231104332673

Spring啓動時讀取應用程序提供的Bean配置信息,並在Spring容器中生成一份相應的Bean配置註冊表,而後根據這張註冊表實例化 Bean,裝配好Bean之間的依賴關係,爲上層應用提供準 備就緒的運行環境.其中Bean緩存池爲HashMap實現node

核心組成

BeanDefinition

是Spring內部的一個接口,定義了對Bean的基本規範(beanClassName、scope、lazyInit等),對象在容器中的抽象;git

Property Explained in…
Class Instantiating Beans
Name Naming Beans
Scope Bean Scopes
Constructor arguments Dependency Injection
Properties Dependency Injection
Autowiring mode Autowiring Collaborators
Lazy initialization mode Lazy-initialized Beans
Initialization method Initialization Callbacks
Destruction method Destruction Callbacks

官方文檔給了以下說明:github

In addition to bean definitions that contain information on how to create a specific bean, the ApplicationContext implementations also permit the registration of existing objects that are created outside the container (by users). This is done by accessing the ApplicationContext’s BeanFactory through the getBeanFactory() method, which returns the BeanFactory DefaultListableBeanFactory implementation. DefaultListableBeanFactory supports this registration through the registerSingleton(..) and registerBeanDefinition(..) methods. However, typical applications work solely with beans defined through regular bean definition metadata.web

機翻:spring

除了包含有關如何建立特定bean的信息的bean定義以外,ApplicationContext實現還容許註冊在容器外部(由用戶)建立的現有對象。這是經過經過方法訪問ApplicationContext的BeanFactory來完成的getBeanFactory(),該方法返回BeanFactory DefaultListableBeanFactory實現。DefaultListableBeanFactory 經過registerSingleton(..)和 registerBeanDefinition(..)方法支持此註冊。可是,典型的應用程序只能與經過常規bean定義元數據定義的bean一塊兒使用。緩存

簡而言之安全

BeanDefinition這個東西怎麼玩呢,經過getBeanFactory().registerBeanDefinition()方式進行註冊(就是put)app

BeanFactory

位於類結構樹的頂端,它最主要的方法就是getBean(String beanName),該方法從容器中返回特定名稱的Bean,BeanFactory的功能經過其餘的接口獲得不斷擴展

image-20191231103355286
image-20191231103355286

ApplicationContext

ApplicationContext由BeanFactory派生而來,提供了更多面向實際應用的功能.ApplicationContext 繼承了HierarchicalBeanFactory和ListableBeanFactory接口,在此基礎上,還經過多個其餘的接口擴展了BeanFactory的功能

image-20191231104029993
image-20191231104029993
  1. FileSystemXmlApplicationContext:默認從文件系統中裝載配置文件

  2. ApplicationEventPublisher:讓容器擁有發佈應用上下文事件的功能,包括容器啓動事

    件、關閉事件等。

  3. MessageSource:爲應用提供 i18n 國際化消息訪問的功能;

  4. ResourcePatternResolver:全部ApplicationContext實現類都實現了相似於

    PathMatchingResourcePatternResolver 的功能,能夠經過帶前綴的 Ant 風格的資源文

    件路徑裝載 Spring 的配置文件。

  5. LifeCycle:該接口是 Spring 2.0 加入的,該接口提供了 start()和 stop()兩個方法,主要

    用於控制異步處理過程。在具體使用時該接口同時被 ApplicationContext 實現及具體 Bean 實現, ApplicationContext 會將 start/stop 的信息傳遞給容器中全部實現了該接 口的 Bean,以達到管理和控制 JMX、任務調度等目的。

  6. ConfigurableApplicationContext 擴展於 ApplicationContext,它新增長了兩個主要 的方法: refresh()和 close(),讓 ApplicationContext 具備啓動、刷新和關閉應用上下文的能力。在應用上下文關閉的狀況下調用 refresh()便可啓動應用上下文,在已經啓動的狀態下,調用 refresh()則清除緩存並從新裝載配置信息,而調用close()則可關閉應用上下文。

原理分析

有了前面的基本概念的介紹,IOC的三板斧

  • bean配置信息封裝到BeanDefinition,並塞進註冊表,怎麼塞?經過getBeanFactory().registerBeanDefinition()
  • 根據註冊表信息解析並實例化bean放進Map緩存裏面
  • 調用者getBean 獲取對應的bean

因此弄清上面三個步驟,大體原理咱們就門清了

demo示例 很簡單

java代碼

@Setter
@Getter
public class AliasDemo {
    private String content;
}
// test方法
@Test
public void testAlias() {
  String configLocation = "application-alias.xml";
  ApplicationContext applicationContext = new ClassPathXmlApplicationContext(configLocation);
  System.out.println("       alias-hello -> " + applicationContext.getBean("alias-hello"));
}
複製代碼

xml配置

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

       default-lazy-init="true">

    <context:component-scan base-package="com.zhangpeng.**"/>
    <bean id="hello" class="com.zhangpeng.study.ioc.alias.AliasDemo">
        <property name="content" value="hello"/>
    </bean>
    <alias name="hello" alias="alias-hello"/>
</beans>
複製代碼

debug

1. IOC配置讀取

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
@Nullable
    private Resource[] configResources;
    ...省略部分源碼...
    // 這是咱們上面例子跳轉進去的構造,傳入一個配置路徑
    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, truenull);
    }
    // 看看重載的構造方法裏面有個setConfigLocations,
    // 那確定就是設置配置路徑了
    // 還有個refresh方法
    public ClassPathXmlApplicationContext(
            String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)

            throws BeansException 
{

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }
}
複製代碼

setConfigLocations主要就是配置一些路徑

2. 核心refresh方法

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

    // Tell the subclass to refresh the internal bean factory.
    // 1.獲取全新的BeanFactory實例
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

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

    try {
      // Allows post-processing of the bean factory in context subclasses.
      postProcessBeanFactory(beanFactory);

      // Invoke factory processors registered as beans in the context.
      invokeBeanFactoryPostProcessors(beanFactory);

      // Register bean processors that intercept bean creation.
      registerBeanPostProcessors(beanFactory);

      // Initialize message source for this context.
      initMessageSource();

      // Initialize event multicaster for this context.
      initApplicationEventMulticaster();

      // Initialize other special beans in specific context subclasses.
      onRefresh();

      // Check for listener beans and register them.
      registerListeners();

      // Instantiate all remaining (non-lazy-init) singletons.
      finishBeanFactoryInitialization(beanFactory);

      // Last step: publish corresponding event.
      finishRefresh();
    }

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

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

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

      // Propagate exception to caller.
      throw ex;
    }

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

2.1 obtainFreshBeanFactory()

@Override
protected final void refreshBeanFactory() throws BeansException {
  if (hasBeanFactory()) {
    destroyBeans();
    closeBeanFactory();
  }
  try {
    DefaultListableBeanFactory beanFactory = createBeanFactory();
    beanFactory.setSerializationId(getId());
    customizeBeanFactory(beanFactory);
    loadBeanDefinitions(beanFactory);
    synchronized (this.beanFactoryMonitor) {
      this.beanFactory = beanFactory;
    }
  }
  catch (IOException ex) {
    throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
  }
}
複製代碼

方法名起的很好,很好理解

  • 進來先銷燬beanFactory 而且建立一個DefaultListableBeanFactory 實例
  • customizeBeanFactory 自定義一些屬性(是否支持BeanDefinition可覆蓋、是否支持循環依賴等)

接着進入loadBeanDefinitions

//org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
  // Create a new XmlBeanDefinitionReader for the given BeanFactory.
  XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

  // Configure the bean definition reader with this context's
  // resource loading environment.
  beanDefinitionReader.setEnvironment(this.getEnvironment());
  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);
}
複製代碼

而後走到doLoadBeanDefinitions,方法名起的很頂啊 xx -> doXx

// 接着看下具體解析的地方
/**
     * Actually load bean definitions from the specified XML file.
     * @param inputSource the SAX InputSource to read from
     * @param resource the resource descriptor for the XML file
     * @return the number of bean definitions found
     * @throws BeanDefinitionStoreException in case of loading or parsing errors
     * @see #doLoadDocument
     * @see #registerBeanDefinitions
     */

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
  throws BeanDefinitionStoreException 
{
 // ...省略...
  try {
    Document doc = doLoadDocument(inputSource, resource);
    int count = registerBeanDefinitions(doc, resource);
    if (logger.isDebugEnabled()) {
      logger.debug("Loaded " + count + " bean definitions from " + resource);
    }
    return count;
  }
    // ...省略...
}
複製代碼

接着看 registerBeanDefinitions

//org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#registerBeanDefinitions
    /**
     * This implementation parses bean definitions according to the "spring-beans" XSD
     * (or DTD, historically).
     * <p>Opens a DOM Document; then initializes the default settings
     * specified at the {@code <beans/>} level; then parses the contained bean definitions.
     */

    @Override
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        doRegisterBeanDefinitions(doc.getDocumentElement());
    }
//org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions
        /**
     * Register each bean definition within the given root {@code <beans/>} element.
     */

    @SuppressWarnings("deprecation")  // for Environment.acceptsProfiles(String...)
    protected void doRegisterBeanDefinitions(Element root) {
        // Any nested <beans> elements will cause recursion in this method. In
        // order to propagate and preserve <beans> default-* attributes correctly,
        // keep track of the current (parent) delegate, which may be null. Create
        // the new (child) delegate with a reference to the parent for fallback purposes,
        // then ultimately reset this.delegate back to its original (parent) reference.
        // this behavior emulates a stack of delegates without actually necessitating one.
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);
      // ...省略...
    // 標準開頭pre前置
        preProcessXml(root);
    // 解析doc
        parseBeanDefinitions(root, this.delegate);
    // 標準結尾post後置
        postProcessXml(root);
        this.delegate = parent;
    }
複製代碼

我擦又來一波doXX,厲害了

spring你個老司機
spring你個老司機

最後看下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);
  }
}
 // 解析默認元素
    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);
        }
    }
// 最終實際解析BeanDefinition的地方
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
  // 這一步採用BeanDefinitionHolder進一步封裝BeanDefinition數據
  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,能夠回答IOC三板斧的第一步的前半個問題,BeanDefinition由配置解析的過程

既然BeanDefinition有了就該註冊,接着上面的代碼繼續走

    /**
     * Register the given bean definition with the given bean factory.
     * @param definitionHolder the bean definition including name and aliases
     * @param registry the bean factory to register with
     * @throws BeanDefinitionStoreException if registration failed
     */

// 經過指定的bean factory註冊,默認就是DefaultListableBeanFactory 
    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);
            }
        }
    }
// org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition
@Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException 
{

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

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

        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }
            else if (existingDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (logger.isInfoEnabled()) {
                    logger.info("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            existingDefinition + "] with [" + beanDefinition + "]");
                }
            }
            else if (!beanDefinition.equals(existingDefinition)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + existingDefinition +
                            "] 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;
                    removeManualSingletonName(beanName);
                }
            }
            else {
                // Still in startup registration phase
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                removeManualSingletonName(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        if (existingDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }
複製代碼

上面這段就是DefaultListableBeanFactory將BeanDefinition塞入map的過程

戰略性總結

obtainFreshBeanFactory方法的獲取過程當中,加載解析BeanDefinition,將BeanDefinition封裝到BeanDefinitionHolder,最後再由DefaultListableBeanFactory註冊BeanDefinition到map

1577785049585
1577785049585

有的老鐵

image-20191231173442143
image-20191231173442143

3.getBean

又是xx & doXx方式

public <T> getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
throws BeansException 
{
    return doGetBean(name, requiredType, args, false);
}

protected <T> doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly)
 throws BeansException 
{
        // 1.移除&開頭字符獲取FactoryBean自己 2.若是是別名將其轉換爲具體實例名
        final String beanName = transformedBeanName(name);
        Object bean;

        // 獲取早期緩存,是否實例化過等價於<=>map.get(beanName) map結構<beanName,bean>
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            if (logger.isTraceEnabled()) {
                if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                            "' that is not fully initialized yet - a consequence of a circular reference");
                }
                else {
                    logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
      // 不爲空就直接返回
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
      // BeanFactory不緩存Prototype類型的bean,處理不了該類型bean的循環依賴問題
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // Check if bean definition exists in this factory.
            BeanFactory parentBeanFactory = getParentBeanFactory();
      // 從父容器查找bean實例
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // Not found -> check parent.
                String nameToLookup = originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory) {
                    return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                            nameToLookup, requiredType, args, typeCheckOnly);
                }
        // 根據有無參數進入對應的getBean重載方法
                else if (args != null) {
                    // Delegation to parent with explicit args.
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else if (requiredType != null) {
                    // No args -> delegate to standard getBean method.
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
                else {
                    return (T) parentBeanFactory.getBean(nameToLookup);
                }
            }

            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }

            try {
        // 合併父子BeanDefinition
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);

                // 檢查是否有依賴的bean
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
            // 循環依賴校驗
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
            // 註冊依賴的bean信息
                        registerDependentBean(dep, beanName);
                        try {
              // 加載依賴的bean
                            getBean(dep);
                        }
                        catch (NoSuchBeanDefinitionException ex) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                        }
                    }
                }

                // 建立bean實例
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            // Explicitly remove instance from singleton cache: It might have been put there
                            // eagerly by the creation process, to allow for circular reference resolution.
                            // Also remove any beans that received a temporary reference to the bean.
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
          // 若是bean是FactoryBean類型,則調用工廠方法獲取真正的bean實例,不然直接返回bean實例
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
                // 建立prototype類型的bean
                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);
                }
                // 建立其餘類型的bean
                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, () -> {
                            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;
            }
        }

        // 檢查是否須要進行類型轉換,須要則轉換而且返回
        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.isTraceEnabled()) {
                    logger.trace("Failed to convert bean '" + name + "' to required type '" +
                            ClassUtils.getQualifiedName(requiredType) + "'", ex);
                }
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        }
        return (T) bean;
    }
複製代碼

將上面的主邏輯收斂一下

image-20200102165520545
image-20200102165520545
  • 1.beanName的轉換

  • 2.從緩存中獲取bean

  • 3.若是實例不爲空&空參構造就調用 getObjectForBeanInstance當即返回

  • 4.不知足3的條件,經過尋找父容器的BeanFactory 查找bean

    不存在經過直接返回父容器找到對應的bean

  • 5.存在該bean,合併父子BeanDefinition

  • 6.處理depends-on依賴的bean,註冊&建立

  • 7.處理FactoryBean (同4的流程)

  • 8.若是須要類型轉換則轉換 最終返回bean

3.1 beanName的轉換

    protected String transformedBeanName(String name) {
        return canonicalName(BeanFactoryUtils.transformedBeanName(name));
    }
  // 剔除&打頭 方便獲取factoryBean自身而不是其具體實現的對象
    public static String transformedBeanName(String name) {
        Assert.notNull(name, "'name' must not be null");
        if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
            return name;
        }
        return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
            do {
                beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
            }
            while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
            return beanName;
        });
    }
    // 別名轉換 由於map不支持<aliasName,Bean> 存儲方式
    public String canonicalName(String name) {
        String canonicalName = name;
        // Handle aliasing...
        String resolvedName;
        do {
            resolvedName = this.aliasMap.get(canonicalName);
            if (resolvedName != null) {
                canonicalName = resolvedName;
            }
        }
        while (resolvedName != null);
        return canonicalName;
    }
複製代碼

關於&的使用 官方文檔裏面提到了 有興趣的同窗能夠去看看

When you need to ask a container for an actual FactoryBean instance itself instead of the bean it produces, preface the bean’s id with the ampersand symbol (&) when calling the getBean() method of the ApplicationContext. So, for a given FactoryBean with an id of myBean, invoking getBean("myBean") on the container returns the product of the FactoryBean, whereas invoking getBean("&myBean") returns the FactoryBean instance itself.
複製代碼

3.2緩存獲取實例

    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                // 主要是爲了防止重複依賴
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                    // 當某些方法須要提早初始化的時候會調用addSingletionFactory 方法將對應的singletonFactory存儲在singletonFactories
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        // 記錄在緩存中,earlySingletonObjects 和 singletonFactories互斥
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return singletonObject;
    }
    /** Cache of singleton objects: bean name to bean instance. */
    // 直接可使用的對象
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    /** Cache of singleton factories: bean name to ObjectFactory. */
    // 用於存放bean工廠,bean工廠所產生的bean是還未完成初始化的bean,bean工廠所生成的對象最終會被緩存到 earlySingletonObjects中
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    // 早期的對象引用(還在初始化中的bean)
    /** Cache of early singleton objects: bean name to bean instance. */
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
複製代碼

這段代碼涉及到循環依賴的處理,後面會單獨寫一篇來闡述

3.3 getObjectForBeanInstance返回

protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd)
 
{
        // 是否以&開頭,是的話就獲取FactoryBean實例
        if (BeanFactoryUtils.isFactoryDereference(name)) {
            if (beanInstance instanceof NullBean) {
                return beanInstance;
            }
      // 不是FactoryBean類型,報錯
            if (!(beanInstance instanceof FactoryBean)) {
                throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
            }
            if (mbd != null) {
                mbd.isFactoryBean = true;
            }
            return beanInstance;
        }
        // name不是以&開頭而且beanInstance不是FactoryBean,說明當前bean是一個普通bean,返回
        if (!(beanInstance instanceof FactoryBean)) {
            return beanInstance;
        }

        Object object = null;
        if (mbd != null) {
            mbd.isFactoryBean = true;
        }
        else {
      // 從緩存獲取
            object = getCachedObjectForFactoryBean(beanName);
        }
        if (object == null) {
            // Return bean instance from factory.
            FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
            // Caches object obtained from FactoryBean if it is a singleton.
            if (mbd == null && containsBeanDefinition(beanName)) {
        // 合併beanDefinition
                mbd = getMergedLocalBeanDefinition(beanName);
            }
            boolean synthetic = (mbd != null && mbd.isSynthetic());
      // 從FactoryBean裏獲取返回
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }

// =========================

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
  if (factory.isSingleton() && containsSingleton(beanName)) {
    synchronized (getSingletonMutex()) {
      Object object = this.factoryBeanObjectCache.get(beanName);
      if (object == null) {
        // 真正調用了factory.getObject()的地方
        object = doGetObjectFromFactoryBean(factory, beanName);
        Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
        if (alreadyThere != null) {
          object = alreadyThere;
        }
        else {
          // 是否應用後置處理器
          if (shouldPostProcess) {
            if (isSingletonCurrentlyInCreation(beanName)) {
              // Temporarily return non-post-processed object, not storing it yet..
              return object;
            }
            beforeSingletonCreation(beanName);
            try {
              // 執行後置處理器
              object = postProcessObjectFromFactoryBean(object, beanName);
            }
            catch (Throwable ex) {
              throw new BeanCreationException(beanName,
                                              "Post-processing of FactoryBean's singleton object failed", ex);
            }
            finally {
              afterSingletonCreation(beanName);
            }
          }
          if (containsSingleton(beanName)) {
            // FactoryBean所建立的實例會被緩存在factoryBeanObjectCache中,供後續調用使用
            this.factoryBeanObjectCache.put(beanName, object);
          }
        }
      }
      return object;
    }
  }
  // 獲取非單例類型的實例
  else {
    // 工廠類獲取
    Object object = doGetObjectFromFactoryBean(factory, beanName);
    // 同上面的 是否須要進行後置處理
    if (shouldPostProcess) {
      try {
        object = postProcessObjectFromFactoryBean(object, beanName);
      }
      catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
      }
    }
    return object;
  }
}
// =========================
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
  throws BeanCreationException 
{

  Object object;
  try {
    // 安全校驗
    if (System.getSecurityManager() != null) {
      // ...省略...
    }
    else {
      // 工廠方法生成實例
      object = factory.getObject();
    }
  }
  // ...省略...
  if (object == null) {
    if (isSingletonCurrentlyInCreation(beanName)) {
      throw new BeanCurrentlyInCreationException(
        beanName, "FactoryBean which is currently in creation returned null from getObject");
    }
    object = new NullBean();
  }
  return object;
}
複製代碼

捋一下上面的步驟,代碼很長,邏輯很清晰

  • 校驗是否&打頭的FactoryBean類型,是的話獲取,不是的話報錯
  • 校驗參數beanInstance不是FactoryBean,說明當前bean是一個普通bean,直接返回
  • 經過緩存獲取FactoryBean
  • 針對單例類型的FactoryBean,未命中,則從FactoryBean.getObject()生成實例並緩存
  • 針對非單例類型的FactoryBean,直接建立新實例,無需緩存
  • 根據shouldPostProcess判斷是否要執行對應的後置處理器

3.4 經過尋找父容器的BeanFactory 查找bean

// 獲取父BeanFactory
BeanFactory parentBeanFactory = getParentBeanFactory();
// 校驗是否不存在該bean
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                  // Not found -> check parent.
                // 當前xml沒找到beanName 對應的信息去parentBeanFactory找
                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 if (requiredType != null) {
                    // No args -> delegate to standard getBean method.
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
                else {
                    return (T) parentBeanFactory.getBean(nameToLookup);
                }
}
複製代碼

3.5 存在該bean,合併父子BeanDefinition

final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
  // Quick check on the concurrent map first, with minimal locking.
  RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
  if (mbd != null && !mbd.stale) {
  return mbd;
  }
  return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
protected RootBeanDefinition getMergedBeanDefinition(
            String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)

            throws BeanDefinitionStoreException 
{

        synchronized (this.mergedBeanDefinitions) {
            RootBeanDefinition mbd = null;
            RootBeanDefinition previous = null;

            // Check with full lock now in order to enforce the same merged instance.
            if (containingBd == null) {
                mbd = this.mergedBeanDefinitions.get(beanName);
            }

            if (mbd == null || mbd.stale) {
                previous = mbd;
                mbd = null;
        // BeanDefinition升級RootBeanDefinition
                if (bd.getParentName() == null) {
                    // Use copy of given root bean definition.
                    if (bd instanceof RootBeanDefinition) {
                        mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
                    }
                    else {
                        mbd = new RootBeanDefinition(bd);
                    }
                }
                else {
                    // Child bean definition: needs to be merged with parent.
                    BeanDefinition pbd;
                    try {
                        String parentBeanName = transformedBeanName(bd.getParentName());
            // 校驗父beanName是否與子類beanName相同,相同parentBeanName確定在map裏
                        if (!beanName.equals(parentBeanName)) {
              // 使用parentBeanName進行與parent的parent合併,以此類推
                            pbd = getMergedBeanDefinition(parentBeanName);
                        }
                        else {
              // 校驗是否是ConfigurableBeanFactory類型 不是就報錯
                            BeanFactory parent = getParentBeanFactory();
                            if (parent instanceof ConfigurableBeanFactory) {
                                pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
                            }
                            else {
                                throw new NoSuchBeanDefinitionException(parentBeanName,
                                        "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                                        "': cannot be resolved without an AbstractBeanFactory parent");
                            }
                        }
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                                "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
                    }
          // 深拷貝的形式 經過父BeanDefinition配置進行合併的BeanDefinition建立
                    mbd = new RootBeanDefinition(pbd);
          // 用子BeanDefinition覆蓋父BeanDefinition屬性
                    mbd.overrideFrom(bd);
                }

        // 配置默認爲單例若是未指定
                if (!StringUtils.hasLength(mbd.getScope())) {
                    mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
                }

                if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
                    mbd.setScope(containingBd.getScope());
                }

                // Cache the merged bean definition for the time being
                // (it might still get re-merged later on in order to pick up metadata changes)
                if (containingBd == null && isCacheBeanMetadata()) {
          // 緩存合併後的definition
                    this.mergedBeanDefinitions.put(beanName, mbd);
                }
            }
            if (previous != null) {
                copyRelevantMergedBeanDefinitionCaches(previous, mbd);
            }
            return mbd;
        }
    }
複製代碼
  • BeanDefinition升級RootBeanDefinition
  • 校驗父beanName是否與子類beanName相同,不一樣再次進行合併
  • 校驗是否是ConfigurableBeanFactory類型 不是就報錯
  • 作了那麼多確定要緩存起來 方便快速使用

3.6 處理depends-on依賴的bean,註冊&建立

// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
  // 遞歸實例化依賴
  for (String dep : dependsOn) {
    // 校驗是否循環依賴,是就拋出異常
    if (isDependent(beanName, dep)) {
      throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                      "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
    }
    // 註冊依賴
    registerDependentBean(dep, beanName);
    try {
      getBean(dep);
    }
    catch (NoSuchBeanDefinitionException ex) {
      throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                      "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
    }
  }
}

/**
 * Register a dependent bean for the given bean,
 * to be destroyed before the given bean is destroyed.
 * @param beanName the name of the bean
 * @param dependentBeanName the name of the dependent bean
 */

public void registerDependentBean(String beanName, String dependentBeanName) {
  // 別名轉換 由於map不支持<aliasName,Bean> 存儲方式
  String canonicalName = canonicalName(beanName);

  synchronized (this.dependentBeanMap) {
    Set<String> dependentBeans =
      this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
    if (!dependentBeans.add(dependentBeanName)) {
      return;
    }
  }
 // set結構進行去重
  synchronized (this.dependenciesForBeanMap) {
    Set<String> dependenciesForBean =
      this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
    dependenciesForBean.add(canonicalName);
  }
}
複製代碼

3.7 處理FactoryBean (同4的流程) 略

3.8 若是須要類型轉換則轉換最終返回bean

代碼過程很好理解 這裏不作深刻探究

小結

getBean這段比較長,這個過程主要就回答了實例化bean並塞進緩存 最後返回使用

技術總結

  • 從IOC原理源碼分析中,xx&doXx的方法命名風格值得在工做中實踐
  • 邏輯抽取的套路值得參考

擴展閱讀

spring官方reference

END

喜歡的能夠一鍵三連,有問題歡迎在留言區評論
原文git

相關文章
相關標籤/搜索