Spring ioc容器的实现

1. 说明

本文将通过源码分析spring ioc容器的实现。

参考书籍《Spring 技术内幕 第二版》

2. 开始

  • 依赖翻转

    首先要明白Spring容器的思想依赖翻转,什么是依赖翻转呢?在面向对象编程中经常会出现一个对象内部引用了另一个对象,这种关系就是对象的依赖关系,通过这种依赖关系,对象之间就可以合作完成各种不同的功能。但是他也有缺陷,如果不同的类相互引用势必会造成代码高度耦合,如何解决这个问题呢?下面是我自己个人的理解。

    通常我们经常会写如下代码

    class A{
        B b=new B();
    }

    这是很典型的一种引用关系,但是假如有一天,B这个类进行了修改,我们使用了一个B1去继承B,然后重写了方法,这个时候我们要对代码进行修改。

    class A{
        B b=new B1();
    }

    但是这种做法并不好,原因有两个,我们需要将所有出现B b=new B()的地方进行更改,显然这样做的成本很高,另外根据面向对象的基本原则中的开闭原则,应该对扩展开放面对修改闭合,也就是说我们可以新增代码,但是不要去修改代码。可是这里不修改似乎不行。

    那我们换一种思路,下面是伪代码。

    class A{
        B b;//这里有一个b成员,但是没有初始化,请根据配置文件通过setB方法为b赋予值
        void setB(B b){
            this.b=b;
        }
    }

    我们站在A类的角度,以前的代码是由A去维护B的引用,而现在确不是了,A类只提供了一个引用,但是这个引用的实际类型是什么并不知道,它需要我们在实例化的时候去设置。

    那么当我们需要用到B1的时候,我们岂不是只要更改一下配置文件就可以完成代码的更新,这样既符合开闭原则,而且A类不与具体的对象相关联,而是与接口相关,这对我们维护代码提供了遍历。

    总结一下前面的分析,我们以前的做法是类主动维护依赖关系,而现在却把维护这种关系的责任交给了类的外部,这种思想便是依赖翻转。

  • Spring IoC

    任何理念思想都应该有产品对象,Spring的核心IoC容器就是这样一个产品,Spring框架中所有的对象都交给IoC容器管理,包括对象之间的依赖关系,如下面代码所示。

  class A{
    @AutoWired
      B b;
  }

通过注解就可以将B的实例注入进对象中,从而完成了对象的依赖关系管理。

那么对于一个IoC容器而言,需要实现什么样的功能呢?

最重要的两个功能应该是

  • 如何获取被管理的对象
  • 如何设置依赖关系
  • BeanFactory和BeanDefinition

解释一下两个最重要的类。

在Spring中,我们通常把由Spring容器管理的对象称为Bean。BeanFactory是Spring中最基本和最核心的接口,顾名思义可以知道这个接口用来管理和创建对象,因此这个接口定义了IoC容器的基本功能,也就是说BeanFactory实际上代表IoC容器,凡是实现了BeanFactory接口的实现类都代表IoC容器,如我们经常通过下面代码获取容器

    ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");

上面的ApplicationContext就是我们所说的容器,而他也是BeanFactory的实现类类。

再看看BeanFactory的源码

  public interface BeanFactory {

      String FACTORY_BEAN_PREFIX = "&";

      Object getBean(String name) throws BeansException;

      Object getBean(String name, Object... args) throws BeansException;

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

      <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

      <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

      boolean containsBean(String name);

      boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

      boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

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

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

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

      String[] getAliases(String name);

  }

BeanFactory最多的方法就是getBean,这符合一个容器的特征。什么是容器呢?现实生活中,容器就是用来装东西的,IoC容器就是用来***ean的,既然里面装着bean,那么我们自然可以把它取出来。

BeanDefinition是什么呢?

IoC容器需要管理对象,其实有两种方法,第一种实现思路是直接管理我们写好的类,如果要获取对象从类中new一个出来就可以了,显然这种方式不太灵活,并且每次都要去判断该对象依赖的对象是什么。另一种实现思路是容器本身管理一种类型,所有用户的类都要转换成容器规定的这种类型,这样的话IoC容器具有什么样的功能取决于容器管理的类型而不是用户写的类。Spring IoC管理的就是容器实现的数据类型,这种类型就是BeanDefinition。

我们通常通过下面的xml文件管理bean。

  <?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      <bean id="testService" class="TestService" scope="singleton"></bean>
  </beans>

对于Spring Ioc来说,会把配置文件中的所有bean标签转化为一个BeanDefinition,然后添加到Spring IoC容器中管理,也就是BeanFactory的实现类。

看一下BeanDefinition的源码

  public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

      String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

      String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

      int ROLE_APPLICATION = 0;

      int ROLE_SUPPORT = 1;

      int ROLE_INFRASTRUCTURE = 2;

      void setParentName(@Nullable String parentName);

      @Nullable
      String getParentName();

      void setBeanClassName(@Nullable String beanClassName);

      @Nullable
      String getBeanClassName();

      void setScope(@Nullable String scope);

      @Nullable
      String getScope();

      void setLazyInit(boolean lazyInit);

      boolean isLazyInit();

      void setDependsOn(@Nullable String... dependsOn);

      @Nullable
      String[] getDependsOn();

      void setAutowireCandidate(boolean autowireCandidate);

      boolean isAutowireCandidate();

      void setPrimary(boolean primary);

      boolean isPrimary();

      void setFactoryBeanName(@Nullable String factoryBeanName);

      @Nullable
      String getFactoryBeanName();

      void setFactoryMethodName(@Nullable String factoryMethodName);

      @Nullable
      String getFactoryMethodName();

      ConstructorArgumentValues getConstructorArgumentValues();

      default boolean hasConstructorArgumentValues() {
          return !getConstructorArgumentValues().isEmpty();
      }

      MutablePropertyValues getPropertyValues();

      default boolean hasPropertyValues() {
          return !getPropertyValues().isEmpty();
      }

      void setInitMethodName(@Nullable String initMethodName);

      @Nullable
      String getInitMethodName();

      void setDestroyMethodName(@Nullable String destroyMethodName);

      @Nullable
      String getDestroyMethodName();

      void setRole(int role);

      int getRole();

      void setDescription(@Nullable String description);

      @Nullable
      String getDescription();

      boolean isSingleton();

      boolean isPrototype();

      boolean isAbstract();

      @Nullable
      String getResourceDescription();

      @Nullable
      org.springframework.beans.factory.config.BeanDefinition getOriginatingBeanDefinition();

  }

可以看到BeanDefinition有很多属性去描述一个bean,比如这个bean属于哪个类,init方法和destroy方法是什么,是否是懒加载,依赖的对象有哪些。

目前我们分析了是谁管理对象,管理的元素是什么,下一个问题是ben的信息放在哪里,从我们使用的角度来看,我们通常可以通过下面的代码获取一个bean

  TestService testService1=context.getBean(TestService.class);
  TestService testService2= (TestService) context.getBean("textService");

通过我们的编程经验,如果要求查找的效率最高,内部应该维护的是HashMap。我们跟踪一下代码找到这个数据结构出来。

  private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

上面的代码是由我们通过跟踪getBean方法发现的,我们的目标是一个单例实例,最终发现其保存在一个ConcurrentHashMap中,由此可见我们的猜想是对的,之所以使用ConcurrentHashMap是为了线程安全问题而考虑的。

目前我们知道了bean是如何描述的,bean是由哪个类管理的,存放bean的具体数据结构是什么。但是距离实现一个IoC容器还面临着不少问题,如:

  • 我们定义的bean是转换成BeanDefinition的。

  • IoC容器什么时候将我们的bean的配置文件转化为map这种数据结构的。

  • 如何通过一个BeanDefinition获取到我们需要的bean对象

    我们至少要解决上面几个问题才能构建出自己的IoC容器处理,下面我们继续分析。

  • refresh方法

    public void refresh() throws BeansException, IllegalStateException {
            synchronized (this.startupShutdownMonitor) {
                // 为refresh过程做准备
                prepareRefresh();
    
                //告诉子类刷新内部bean工厂,完成该步骤,bean就会进入到容器内部
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
                //准备bean工厂在此上下文中使用做准备
                prepareBeanFactory(beanFactory);
    
                try {
                    // 允许在上下文子类中对bean工厂进行后处理。
                    postProcessBeanFactory(beanFactory);
    
                    // 调用作为bean注册进上下文的处理器
                    invokeBeanFactoryPostProcessors(beanFactory);
    
                    // 注册拦截bean创建的bean处理器。
                    registerBeanPostProcessors(beanFactory);
    
                    // 初始化此上下文的消息源
                    initMessageSource();
    
                    // 初始化此上下文的事件多播器。
                    initApplicationEventMulticaster();
    
                    // 在特定的上下文子类中初始化其他特殊bean。
                    onRefresh();
    
                    // 检查***bean并注册它们。
                    registerListeners();
    
                    // 实例化所有剩余(非延迟初始化)单例。
                    finishBeanFactoryInitialization(beanFactory);
    
                    // 最后一步:发布相应的事件。
                    finishRefresh();
                }
    
                catch (BeansException ex) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Exception encountered during context initialization - " +
                                "cancelling refresh attempt: " + ex);
                    }
    
                    // 摧毁已经创建的单例以避免悬空资源。
                    destroyBeans();
    
                    // 重置 'active' 标记.
                    cancelRefresh(ex);
    
                    //向调用者传播异常
                    throw ex;
                }
    
                finally {
                    // 重置Spring核心中的常见内省缓存, 因为我们不再需要单例bean的元数据
                    resetCommonCaches();
                }
            }
        }

    上面refresh方法的注释是根据源码注释翻译过来的,可以看出refresh方法与容器初始化密切相关。

    IoC容器的初始化的关键在于BeanFactory的获取,通过对代码

    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();的跟踪发现如下方法:

        @Override
        protected final void refreshBeanFactory() throws BeansException {
            //如果存在BeanFactory就销毁
            if (hasBeanFactory()) {
                destroyBeans();
                closeBeanFactory();
            }
            try {
                //创建BeanFactory
                DefaultListableBeanFactory beanFactory = createBeanFactory();
                beanFactory.setSerializationId(getId());
                customizeBeanFactory(beanFactory);
                //加载BeanDefinition
                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,加载BeanDefinition。

    容器的初始化首先应该创建容器,我们继续跟踪BeanFactory的创建。

    protected DefaultListableBeanFactory createBeanFactory() {
            return new DefaultListableBeanFactory(getInternalParentBeanFactory());
    }

    可以发现是直接返回来一个DefaultListableBeanFactory;此时获得的BeanFactory是空的,里面什么信息都没有,需要loadBeanDefinitions加载。

    @Override
        protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
            //为传入的BeanFactory参数创建一个XmlBeanDefinitionReader
            XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    
            // 使用此上下文的资源加载环境配置bean定义读取器。
            beanDefinitionReader.setEnvironment(this.getEnvironment());
            beanDefinitionReader.setResourceLoader(this);
            beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    
            //允许子类提供reader的自定义初始化,然后继续实际加载bean定义。
            initBeanDefinitionReader(beanDefinitionReader);
            //加载BeanDefinition
            loadBeanDefinitions(beanDefinitionReader);
        }

    从该方法可以看出,BeanDefinition的加载与BeanDefinitionReader关系非常大。

        protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
            //获取resource
            Resource[] configResources = getConfigResources();
            if (configResources != null) {
                reader.loadBeanDefinitions(configResources);
            }
            //获取配置文件的位置,这一步实际上拿到了我们spring.xml的路径信息
            String[] configLocations = getConfigLocations();
            if (configLocations != null) {
                //通过reader的loadBeanDefinitions方法,参数为配置信息的位置加载beanDefinition
                reader.loadBeanDefinitions(configLocations);
            }
        }

    到了这一步,IoC容器的初始化过程已经非常明显了,现在留给我们的问题只有两个,配置文件是如何获取的,如何加载的,这些问题与getConfigLocations方法和readerloadBeanDefinitions方法有关。

  • 资源定位

    bean的配置信息我们一般写在配置文件中,容器管理bean的自然要找到配置信息。通过下面这行代码的分析

    ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");

    配置文件是写在构造方法参数中的,并且ClassPathXmlApplicationContext意味着从ClassPath加载该文件。

    public ClassPathXmlApplicationContext(
                String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
                throws BeansException {
    
            super(parent);
            //设置配置文件的位置
            setConfigLocations(configLocations);
            if (refresh) {
                refresh();
            }
        }
    public void setConfigLocations(@Nullable String... locations) {
        if (locations != null) {
            Assert.noNullElements(locations, "Config locations must not be null");
            this.configLocations = new String[locations.length];
            for (int i = 0; i < locations.length; i++) {
                this.configLocations[i] = resolvePath(locations[i]).trim();
            }
        }
        else {
            this.configLocations = null;
        }
    }

    通过构造方法,location信息已经保存在configLocations了,然后回到上一节的末尾方法;

    protected String[] getConfigLocations() {
            return (this.configLocations != null ? this.configLocations :getDefaultConfigLocations());
    }

    可以看到是直接返回的,如果我们没有传入配置文件路径,那么他会返回一个默认的位置(这个默认的位置其实是null);

    现在已经拿到了配置文件的路径,但是本节开始说过一个问题ClassPathXmlApplicationContext就是从ClassPath下加载该文件,这里我们只有文件路径信息,但是IoC容器如何直到从哪里加载该信息呢?

    继续跟踪代码

        public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
            //获取一个ResourceLoader
            ResourceLoader resourceLoader = getResourceLoader();
            if (resourceLoader == null) {
                throw new BeanDefinitionStoreException(
                        "Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
            }
    
            if (resourceLoader instanceof ResourcePatternResolver) {
                // Resource pattern matching available.
                try {
                    //通过ResourceLoader的getResources方法,以配置文件位置信息获取resource
                    Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                    //以resource为参数加载BeanDefinition
                    int count = loadBeanDefinitions(resources);
                    if (actualResources != null) {
                        Collections.addAll(actualResources, resources);
                    }
                    if (logger.isTraceEnabled()) {
                        logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
                    }
                    return count;
                }
                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 count = loadBeanDefinitions(resource);
                if (actualResources != null) {
                    actualResources.add(resource);
                }
                if (logger.isTraceEnabled()) {
                    logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
                }
                return count;
            }
        }

    Resource对象就是配置文件的封装,获取到了resource就相当于准确定位到了配置文件。

  • 载入和解析

    获取到了Resource对象就可以完成BeanDefinition的载入和解析了,这个过程将配置文件的信息加载进入IoC容器,然后通过这些信息获取到具体的BeanDefinition实例。

    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
            Assert.notNull(encodedResource, "EncodedResource must not be null");
            if (logger.isTraceEnabled()) {
                logger.trace("Loading XML bean definitions from " + encodedResource);
            }
    
            Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
            if (currentResources == null) {
                currentResources = new HashSet<>(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(inputSource, encodedResource.getResource())语句

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
                throws BeanDefinitionStoreException {
    
            try {
                //将配置文件解析成Document对象
                Document doc = doLoadDocument(inputSource, resource);
                //-> 进入该方法
                int count = registerBeanDefinitions(doc, resource);
                if (logger.isDebugEnabled()) {
                    logger.debug("Loaded " + count + " bean definitions from " + resource);
                }
                return count;
            }
            catch (BeanDefinitionStoreException ex) {
                throw ex;
            }
            catch (SAXParseException ex) {
                throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                        "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
            }
            catch (SAXException ex) {
                throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                        "XML document from " + resource + " is invalid", ex);
            }
            catch (ParserConfigurationException ex) {
                throw new BeanDefinitionStoreException(resource.getDescription(),
                        "Parser configuration exception parsing XML from " + resource, ex);
            }
            catch (IOException ex) {
                throw new BeanDefinitionStoreException(resource.getDescription(),
                        "IOException parsing XML document from " + resource, ex);
            }
            catch (Throwable ex) {
                throw new BeanDefinitionStoreException(resource.getDescription(),
                        "Unexpected exception parsing XML document from " + resource, ex);
            }
        }
    

    进入int count = registerBeanDefinitions(doc, resource);语句

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        //获取一个BeanDefinitionDocumentReader对象
            BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
            int countBefore = getRegistry().getBeanDefinitionCount();
        //调用documentReader的方法 -> 进入该方法
            documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
            return getRegistry().getBeanDefinitionCount() - countBefore;
    }

    继续documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
            this.readerContext = readerContext;
        //->
            doRegisterBeanDefinitions(doc.getDocumentElement());
    }

    继续doRegisterBeanDefinitions(doc.getDocumentElement());

        protected void doRegisterBeanDefinitions(Element root) {
            //BeanDefinitionParserDelegate真正完成解析工作
            BeanDefinitionParserDelegate parent = this.delegate;
            this.delegate = createDelegate(getReaderContext(), root, parent);
    
            if (this.delegate.isDefaultNamespace(root)) {
                String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
                if (StringUtils.hasText(profileSpec)) {
                    String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                            profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                    if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                    "] not matching: " + getReaderContext().getResource());
                        }
                        return;
                    }
                }
            }
    
            preProcessXml(root);
            //解析BeanDefinition ->
            parseBeanDefinitions(root, this.delegate);
            postProcessXml(root);
    
            this.delegate = parent;
        }

    继续parseBeanDefinitions(root, this.delegate);

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

    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)) {
                //如果ele元素是一个Bean的话,调用下面的方法
                processBeanDefinition(ele, delegate);
            }
            else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
                // recurse
                doRegisterBeanDefinitions(ele);
            }
        }

    继续processBeanDefinition(ele, delegate);

        protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
            //通过delegate的parseBeanDefinitionElement方法获取BeanDefinitionHolder实例
            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));
            }
        }

    继续delegate.parseBeanDefinitionElement(ele);

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
            //获取bean的id
            String id = ele.getAttribute(ID_ATTRIBUTE);
            //获取bean的名称
            String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    
            List<String> aliases = new ArrayList<>();
            if (StringUtils.hasLength(nameAttr)) {
                String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                aliases.addAll(Arrays.asList(nameArr));
            }
    
            String beanName = id;
            if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
                beanName = aliases.remove(0);
                if (logger.isTraceEnabled()) {
                    logger.trace("No XML 'id' specified - using '" + beanName +
                            "' as bean name and " + aliases + " as aliases");
                }
            }
    
            if (containingBean == null) {
                checkNameUniqueness(beanName, aliases, ele);
            }
    
            AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
            if (beanDefinition != null) {
                if (!StringUtils.hasText(beanName)) {
                    try {
                        if (containingBean != null) {
                            beanName = BeanDefinitionReaderUtils.generateBeanName(
                                    beanDefinition, this.readerContext.getRegistry(), true);
                        }
                        else {
                            beanName = this.readerContext.generateBeanName(beanDefinition);
                            // Register an alias for the plain bean class name, if still possible,
                            // if the generator returned the class name plus a suffix.
                            // This is expected for Spring 1.2/2.0 backwards compatibility.
                            String beanClassName = beanDefinition.getBeanClassName();
                            if (beanClassName != null &&
                                    beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                    !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                                aliases.add(beanClassName);
                            }
                        }
                        if (logger.isTraceEnabled()) {
                            logger.trace("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);
                //将BeanDefinition封装成一个BeanDefinitionHolder对象返回
                return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
            }
    
            return null;
        }

    上面的方法结束,就获取到了一个BeanDefinition

    根据返回语句return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);可知到这一步配置文件中的bean已经转化为一个BeanDefinition了

  • 注册

    BeanDefinition已经获取到了,现在要做的试将BeanDefinition保存在IoC容器中,这一步就发送在BeanDefinitionHolder获取之后。

    public static void registerBeanDefinition(
                BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
                throws BeanDefinitionStoreException {
    
            // 使用初始的名称注册
            String beanName = definitionHolder.getBeanName();
            //-> 进入方法
            registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
            // 注册别名
            String[] aliases = definitionHolder.getAliases();
            if (aliases != null) {
                for (String alias : aliases) {
                    registry.registerAlias(beanName, alias);
                }
            }
        }
    

    继续registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());,这个方法将beanName和BeanDefinition作为参数传入,可以预料到最终的注册就发送在这个方法中。

    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
                throws BeanDefinitionStoreException {
            //断言校验beanName和beanDefinition是否有问题
            Assert.hasText(beanName, "Bean name must not be empty");
            Assert.notNull(beanDefinition, "BeanDefinition must not be null");
            //判断BeanDefinition是不是AbstractBeanDefinition类型的
            if (beanDefinition instanceof AbstractBeanDefinition) {
                try {
                    ((AbstractBeanDefinition) beanDefinition).validate();
                }
                catch (BeanDefinitionValidationException ex) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                            "Validation of bean definition failed", ex);
                }
            }
            //判断已经存在同名的BeanDefinition
            BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
            if (existingDefinition != null) {
                if (!isAllowBeanDefinitionOverriding()) {
                    throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
                }
                else if (existingDefinition.getRole() < beanDefinition.getRole()) {
                    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()) {
                    synchronized (this.beanDefinitionMap) {
                        //将beanName作为key,BeanDefinition作为value保存在HashMap中
                        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);
            }
        }

    this.beanDefinitionMap.put(beanName, beanDefinition);将BeanDefinition保存到了文章最开始猜想的HashMap中,此时BeanDefinition已经保存到了IoC容器中。

  • 依赖注入

    依赖注入发生在第一次获取Bean的时候,注意完成了上一步,IoC容器中存放的并不是bean对象而是BeanDefinition,从BeanDefinition信息获取bean对象就是依赖注入的过程。

    通过beanFactory的getBean方法获取,这里我们以beanName作为参数。

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

    进入doGetBean方法

    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    
            final String beanName = transformedBeanName(name);
            Object bean;
    
            // 单例对象会放到缓存中,所以先去缓存中获取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 + "'");
                    }
                }
                //从factoryBean对象中获取bean
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
            }
            else {
                // Fail if we're already creating this bean instance:
                // We're assumably within a circular reference.
                if (isPrototypeCurrentlyInCreation(beanName)) {
                    throw new BeanCurrentlyInCreationException(beanName);
                }
    
                // 检查对应的BeanDefinition是否存在
                BeanFactory parentBeanFactory = getParentBeanFactory();
                if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                    // 如果当前BeanFactory中不能存在,并且有父BeanFactory则检查父BeanFactory
                    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);
                    }
                }
    
                if (!typeCheckOnly) {
                    markBeanAsCreated(beanName);
                }
    
                try {
                    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                    checkMergedBeanDefinition(mbd, beanName, args);
    
                    // 保证当前bean依赖的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 + "'");
                            }
                            registerDependentBean(dep, beanName);
                            try {
                                getBean(dep);
                            }
                            catch (NoSuchBeanDefinitionException ex) {
                                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                            }
                        }
                    }
    
                    // 创建bean实例
                    //如果当前bean是一个单例
                    if (mbd.isSingleton()) {
                        sharedInstance = getSingleton(beanName, () -> {
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            catch (BeansException ex) {
                                destroySingleton(beanName);
                                throw ex;
                            }
                        });
                        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                    }
    
                    else if (mbd.isPrototype()) {
                        // 如果是prototype类型 -> 创建一个新的实例.
                        Object prototypeInstance = null;
                        try {
                            beforePrototypeCreation(beanName);
                            prototypeInstance = createBean(beanName, mbd, args);
                        }
                        finally {
                            afterPrototypeCreation(beanName);
                        }
                        bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                    }
    
                    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;
                }
            }
    
            // Check if required type matches the type of the actual bean instance.
            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;
        }
    

3. 总结

spring IoC容器是spring框架的核心,spring IoC管理着spring框架的bean,是spring mvc等其他框架的基石,只有充分理解IoC的原理,才能对框架本身理解的更加透彻。