Spring-IOC过程源码解析

13次阅读

共计 19512 个字符,预计需要花费 49 分钟才能阅读完成。

废话不多说,我们先做一个傻瓜版的 IOC demo 作为例子

自定义的 Bean 定义

class MyBeanDefinition{

    public String id;
    public String className;
    public String value;

    public MyBeanDefinition(String id, String className, String value) {
        this.id = id;
        this.className = className;
        this.value = value;
    }

}

自定义的 Bean 工厂


class MyBeanFactory {Map<String, Object> beanMap = new HashMap<>();

    public MyBeanFactory(MyBeanDefinition beanDefinition) throws ClassNotFoundException,
            IllegalAccessException, InstantiationException {Class<?> beanClass = Class.forName(beanDefinition.className);
        Object bean = beanClass.newInstance();
        ((UserService) bean).setName(beanDefinition.value);
        beanMap.put(beanDefinition.id, bean);

    }

    public Object getBean(String id) {return beanMap.get(id);
    }


}

测试傻瓜版 IOC 容器

public class EasyIOC {public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {

        MyBeanDefinition beanDefinition = new MyBeanDefinition("userService",
                "com.valarchie.UserService", "archie");

        MyBeanFactory beanFactory = new MyBeanFactory(beanDefinition);
        UserService userService = (UserService) beanFactory.getBean("userService");

        System.out.println(userService.getName());

    }


}

看完以上这个傻瓜版的例子我们可以思考一下?让我们自己实现 IOC 的容器的关键是什么呢?

按照我的理解,我总结为以下三步

  • 读取 xml 文件形成 DOM 对象
  • 读取 DOM 文档对象里的 Bean 定义并装载进 BeanFactory 中
  • 根据 bean 定义生成实例放进容器,以供使用

所以,接下来我们不会通盘分析整个 IOC 的流程,因为旁枝细节太多读者看完也云里雾里抓不到重点。
我们通过分析最重要的这条代码主干线来理解 IOC 的过程。

开始分析:

首先我们从 xml 的配置方式开始分析,因为 Spring 最初的配置方式就是利用 xml 来进行配置,所以大部分人对 xml 的配置形式较为熟悉,也比较方便理解。

从 ClassPathXmlApplicationContext 的构造器开始讲起。

public class TestSpring {public static void main(String[] args) {
        // IOC 容器的启动就从 ClassPathXmlApplicationContext 的构造方法开始
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
        UserService userService = (UserService) context.getBean("userService");
        System.out.println(userService.getName());
       
    }
}

进入到构造方法中,调用重载的另一个构造方法。

// 创建 ClassPathXmlApplicationContext,加载给定的位置的 xml 文件,并自动刷新 context
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {this(new String[] {configLocation}, true, null);
}

重载的构造方法中,由于刚才 parrent 参数传为 null,所以不设置父容器。refresh 刚才设置为 true,流程就会进入 refresh() 方法中

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {
        // 由于之前的方法调用将 parent 设置为 null,所以我们就不分析了
        super(parent);
        // 设置路径数组,并依次对配置路径进行简单占位符替换处理,比较简单,我们也不进入分析了
        setConfigLocations(configLocations);
        if (refresh) {refresh();
        }
}

整个 refresh() 方法中就是 IOC 容器启动的主干脉络了,Spring 采用了模板方法设计模式进行 refresh() 方法的设计,先规定好整个 IOC 容器的具体步骤,然后将每一个小步骤由各种不同的子类自己实现。

所有重要的操作都是围绕着 BeanFactory 在进行。
在注释当中,我们详细的列出了每一步方法所完成的事情。ApplicationContext 内部持有了 FactoryBean 的实例。其实 ApplicationContext 本身最上层的父接口也是 BeanFactory,他拓展了 BeanFactory 之外的功能(提供国际化的消息访问、资源访问,如 URL 和文件、事件传播、载入多个(有继承关系)上下文)

我们先通过阅读代码中的注释来了解大概的脉络。

public void refresh() throws BeansException, IllegalStateException {
        // 先加锁防止启动、结束冲突
        synchronized (this.startupShutdownMonitor) {
            // 在刷新之前做一些准备工作
            // 设置启动的时间、相关状态的标志位(活动、关闭)、初始化占位符属性源,并确认
            // 每个标记为必须的属性都是可解析的。prepareRefresh();

            // 获取一个已刷新的 BeanFactory 实例。ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // 定义好 Bean 工厂的环境特性,例如类加载器,或者后置处理器
            prepareBeanFactory(beanFactory);

            try {
                // 设置在 BeanFactory 完成初始化之后做一些后置操作,spring 留给子类的扩展。postProcessBeanFactory(beanFactory);

                // 启动之前已设置的 BeanFactory 后置处理器
                invokeBeanFactoryPostProcessors(beanFactory);

                // 注册 Bean 处理器
                registerBeanPostProcessors(beanFactory);

                // 为我们的应用上下文设置消息源(i18n)initMessageSource();

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

                // 初始化特殊的 Bean 在特殊的 Context 中,默认实现为空,交给各个具体子类实现
                onRefresh();

                // 检查监听器并注册
                registerListeners();

                // 实例化所有非懒加载的 Bean
                finishBeanFactoryInitialization(beanFactory);

                // 最后一步发布相应的事件
                finishRefresh();}

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

                // 如果启动失败的话,要销毁之前创建的 Beans。destroyBeans();

                // 重置 ApplicationContext 内部 active 的标志位
                cancelRefresh(ex);

                // 向调用者抛出异常
                throw ex;
            }

            finally {
                // 重置 Spring 核心内的缓存,因为我们可能不再需要单例 bean 相关的元数据
                resetCommonCaches();}
        }
    }

阅读完之后我们重点关注 obtainFreshBeanFactory()、finishBeanFactoryInitialization(beanFactory) 这两个方法,因为实质上整个 IOC 的流程都在这两个方法当中,其他的方法一部分是 Spring 预留给用户的自定义操作如 BeanFactory 的后置处理器和 Bean 后置处理器,一部分是关键启动事件的发布和监听操作,一部分是关于 AOP 的操作。

首先,先从 obtainFreshBeanFactory() 开始说起。

第一步:读取 xml 文件形成 DOM 对象

在 getBeanFactory() 方法之前,先调用 refreshBeanFactory() 方法进行刷新。我们先说明一下,getBeanFactory() 非常简单,默认实现只是将上一步刷新成功好构建好的 Bean 工厂进行返回。返回出去的 Bean 工厂已经加载好 Bean 定义了。所以在 refreshBeanFactory() 这个方法中已经包含了第一步读取 xml 文件构建 DOM 对象和第二步解析 DOM 中的元素生成 Bean 定义进行保存。记住,这里仅仅是保存好 Bean 定义,此时并未涉及 Bean 的实例化。

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

进入 refreshBeanFactory() 方法中

protected final void refreshBeanFactory() throws BeansException {
        // 如果当前 ApplicationContext 中已存在 FactoryBean 的话进行销毁
        if (hasBeanFactory()) {destroyBeans();
            closeBeanFactory();}
        try {
            // 先生成一个 BeanFactory
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            // 设置序列化
            beanFactory.setSerializationId(getId());
            // 设置是否可以覆盖 Bean 定义和是否可以循环依赖,具体我就不解释了
            customizeBeanFactory(beanFactory);
            // 加载 Bean 定义到 Factory 当中去
            // 重点!loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}
        }
        catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for" + getDisplayName(), ex);
        }
    }

接下来,进入核心方法 loadBeanDefinitions(beanFactory) 中,参数是刚创建的 beanFactory

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // 根据传入的 beanfactory 创建一个 xml 读取器
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    
        // 设置 bean 定义读取器的相关资源加载环境
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // 这个方法让子类自定义读取器 Reader 的初始化
        initBeanDefinitionReader(beanDefinitionReader);
        // 接着开始实际加载 Bean 定义
        loadBeanDefinitions(beanDefinitionReader);
    }

进入 loadBeanDefinitions(beanDefinitionReader) 方法中,参数是刚刚创建好的 Reader 读取器。

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        // 如果有已经生成好的 Resouce 实例的话就直接进行解析。// 默认的实现是返回 null,由子类自行实现。Resource[] configResources = getConfigResources();
        if (configResources != null) {reader.loadBeanDefinitions(configResources);
        }
        // 没有 Resouces 的话就进行路径解析。String[] configLocations = getConfigLocations();
        if (configLocations != null) {reader.loadBeanDefinitions(configLocations);
        }
}

我们进入 reader.loadBeanDefinitions(configLocations) 方法中,这里面方法调用有点绕,我这边只简单地描述一下

该方法会根据多个不同位置的 xml 文件依次进行处理。
接着会对路径的不同写法进行不同处理,例如 classpath 或者 WEB-INF 的前缀路径。
根据传入的 locations 变量生成对应的 Resouces。
紧接着进入 reader.loadBeanDefinitions(resource) 此时参数是 Resource。
在经过一层进入 loadBeanDefinitions(new EncodedResource(resource)) 的方法调用中。

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());
    }
    // 通过 ThreadLocal 实现的当前 currentResource
    Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
    if (currentResources == null) {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() 方法。

// 内部核心代码就这两句
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
        

在 loadDocument() 方法中会生成一个 DocumentBuilderImpl 对象,这个对象会调用 parse 方法,在 parse 方法中使用 SAX 进行解析刚才的输入流包装的 InputSource,生成 DOM 对象返回。

public Document parse(InputSource is) throws SAXException, IOException {if (is == null) {
            throw new IllegalArgumentException(
                DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
                "jaxp-null-input-source", null));
        }
        if (fSchemaValidator != null) {if (fSchemaValidationManager != null) {fSchemaValidationManager.reset();
                fUnparsedEntityHandler.reset();}
            resetSchemaValidator();}
        // 解析 xml
        domParser.parse(is);
        // 获取刚才解析好的 dom
        Document doc = domParser.getDocument();
        domParser.dropDocumentReferences();
        return doc;
}

此时我们的 xml 文件已经加载并解析成 DOM 结构对象了,第一步已经完成了。

第二步:读取 DOM 文档对象里的 Bean 定义并装载进 BeanFactory 中

// 内部核心代码就这两句
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
        

我们再回到刚刚讲到的这两句核心代码,第一句获取 DOM 对象后,紧接着第二句 registerBeanDefinitions(doc, resource) 开始了 bean 定义的注册工作。

进入 registerBeanDefinitions(doc, resource) 方法中

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        // 生成 DOM 读取器,这个和刚才的读取器不一样,之前的读取器是 xml 读取器。BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        // 获取之前的 bean 定义数量 
        int countBefore = getRegistry().getBeanDefinitionCount();
        
        // 进入重点
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        
        // 用刚刚又创建的 bean 定义数量 - 之前的 bean 定义数量 = 刚刚一共创建的 bean 定义 
        return getRegistry().getBeanDefinitionCount() - countBefore;
}

进入 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)) 方法。
方法内读取文档的 root 元素。

protected void doRegisterBeanDefinitions(Element root) {
        // Any nested <beans> elements will cause recursion in this method. In
        // order to propagate and preserve <beans> default-* attributes correctly,
        // keep track of the current (parent) delegate, which may be null. Create
        // the new (child) delegate with a reference to the parent for fallback purposes,
        // then ultimately reset this.delegate back to its original (parent) reference.
        // this behavior emulates a stack of delegates without actually necessitating one.
        BeanDefinitionParserDelegate parent = this.delegate;
        
        // 生成 Bean 定义解析类
        this.delegate = createDelegate(getReaderContext(), root, parent);

        // 如果是 xml 文档中的 namespace,进行相应处理
        if (this.delegate.isDefaultNamespace(root)) {String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {if (logger.isInfoEnabled()) {
                        logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching:" + getReaderContext().getResource());
                    }
                    return;
                }
            }
        }

        // spring 预留给子类的拓展性方法
        preProcessXml(root);
        
        // 重点
        // 开始解析 Bean 定义
        parseBeanDefinitions(root, this.delegate);
        
      // spring 预留给子类的拓展性方法
        postProcessXml(root);

        this.delegate = parent;
        
}

进入 parseBeanDefinitions(root, this.delegate)。将之前的文档对象和 bean 定义解析类作为参数传入。

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 {
            // 非默认命名空间的,进行自定义解析,命名空间就是 xml 文档头内的 xmlns,用来定义标签。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)) {
            // 分析 Bean 标签
            processBeanDefinition(ele, delegate);
        }
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // recurse
            doRegisterBeanDefinitions(ele);
        }
}

我们主要分析 Bean 元素标签的解析,进入 processBeanDefinition(ele, delegate) 方法中最内层。

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        // 获取 bean 标签内的 id
        String id = ele.getAttribute(ID_ATTRIBUTE);
        // 获取 bean 标签内的 name
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

        // 设置多别名
        List<String> aliases = new ArrayList<String>();
        if (StringUtils.hasLength(nameAttr)) {String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }

        // 当没有设置 id 的时候
        String beanName = id;
        if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {beanName = aliases.remove(0);
            if (logger.isDebugEnabled()) {
                logger.debug("No XML'id'specified - using'" + beanName +
                        "'as bean name and" + aliases + "as aliases");
            }
        }

        // 检查 beanName 是否唯一
        if (containingBean == null) {checkNameUniqueness(beanName, aliases, ele);
        }
        // 内部做了 Bean 标签的解析工作
        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
        if (beanDefinition != null) {if (!StringUtils.hasText(beanName)) {
                try {if (containingBean != null) {
                        beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
                    }
                    else {beanName = this.readerContext.generateBeanName(beanDefinition);
                        // Register an alias for the plain bean class name, if still possible,
                        // if the generator returned the class name plus a suffix.
                        // This is expected for Spring 1.2/2.0 backwards compatibility.
                        String beanClassName = beanDefinition.getBeanClassName();
                        if (beanClassName != null &&
                                beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {aliases.add(beanClassName);
                        }
                    }
                    if (logger.isDebugEnabled()) {
                        logger.debug("Neither XML'id'nor'name'specified -" +
                                "using generated bean name [" + beanName + "]");
                    }
                }
                catch (Exception ex) {error(ex.getMessage(), ele);
                    return null;
                }
            }
            String[] aliasesArray = StringUtils.toStringArray(aliases);
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }

        return null;
}

将解析好的 Bean 定义并附加别名数组填入 new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray) 中进行返回。然后调用以下这个方法。

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

最主要的操作就是将刚才解析好的 Bean 定义放入 beanDefinitionMap 中去。

解析成功后将 Bean 定义进行保存。第二步也已经完成。

第三步:使用创建好的 Bean 定义,开始实例化 Bean。

我们回到最开始的 refresh 方法中,在 finishBeanFactoryInitialization(beanFactory) 方法中,开始实例化非懒加载的 Bean 对象。我们跟着调用链进入到 preInstantiateSingletons() 方法中

@Override
public void preInstantiateSingletons() throws BeansException {if (this.logger.isDebugEnabled()) {this.logger.debug("Pre-instantiating singletons in" + this);
    }

    // 将之前做好的 bean 定义名列表拷贝放进 beanNames 中,然后开始遍历
    List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

    // 触发所有非懒加载的单例 Bean 实例化
    for (String beanName : beanNames) {RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        
        // 如果非抽象并且是单例和非懒加载的话
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            // 检测是否是工厂方法 Bean。创建 Bean 的不同方式,读者可自行百度。if (isFactoryBean(beanName)) {final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
                boolean isEagerInit;
                if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                        @Override
                        public Boolean run() {return ((SmartFactoryBean<?>) factory).isEagerInit();}
                    }, getAccessControlContext());
                }
                else {
                    isEagerInit = (factory instanceof SmartFactoryBean &&
                            ((SmartFactoryBean<?>) factory).isEagerInit());
                }
                if (isEagerInit) {getBean(beanName);
                }
            }
            else {getBean(beanName);
            }
        }
    }

    // 关于实例化之后做的自定义操作代码省略....
}

在该方法中根据 Bean 实例是通过工厂方法实例还是普通实例化,最主要的方法还是 getBean(beanName) 方法。我们继续分析普通实例化的过程。进入 getBean() 方法当中 doGetBean() 方法,发现方法参数 doGetBean(name, null, null, false) 后三个参数全部为 null, 它就是整个 IOC 中的核心代码。

代码中先通过实例化 Bean, 实例化好之后再判断该 Bean 所需的依赖,并递归调用进行实例化 bean,成功后整个 IOC 的核心流程也就完成了。

protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
        throws BeansException {final String beanName = transformedBeanName(name);
    Object bean;

    // Eagerly check singleton cache for manually registered singletons.
    Object sharedInstance = getSingleton(beanName);
    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 + "'");
            }
        }
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    else {
        // 如果当前 Bean 正在创建中的话就直接失败,// 可以陷入了循环引用。if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);
        }

        // 检测 Bean 定义是否出现在父 Bean 工厂
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // 父工厂不为 null 并且当前不包含这个 Bean 定义时
            // 从父工厂去返回 Bean
            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) {markBeanAsCreated(beanName);
        }

        try {
            // 将子 Bean 定义与父 Bean 定义进行整合
            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);
                    }
                }
            }

            // 如果是单例的话
            if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                    @Override
                    public Object getObject() throws BeansException {
                        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 = 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);
            }
                    // 非单例和原型 范围的情况
            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;
        }
    }

    // 检测实例 Bean 的类型和所需类型是否一致
    if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
        try {return getTypeConverter().convertIfNecessary(bean, requiredType);
        }
        catch (TypeMismatchException ex) {if (logger.isDebugEnabled()) {
                logger.debug("Failed to convert bean'" + name + "'to required type'" +
                        ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    return (T) bean;
}

根据 Bean 定义去实例化 Bean。第三步也已经完成。

文章篇幅有限,IOC 整个的创建过程还是比较冗长的,希望读者看完文章对 IOC 的创建过程有一个主干脉络的思路之后还是需要翻开源码进行解读,其实阅读源码并不难,因为 Spring 的代码注释都挺健全,如果遇到不清楚的稍微 google 一下就知道了。建议读者自己试着一步一步的分析 IOC 过程的源码。

转自我的个人博客 vc2x.com

正文完
 0