03spring源码分析-IOC初始化容器过程分析

入口:

public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, ApplicationContext parent)
            throws BeansException {

        super(parent);
        Assert.notNull(paths, "Path array must not be null");
        Assert.notNull(clazz, "Class argument must not be null");
        this.configResources = new Resource[paths.length];
        for (int i = 0; i < paths.length; i++) {
            this.configResources[i] = new ClassPathResource(paths[i], clazz);
        }
        refresh();
    }

主要方法就是refresh方法进行IOC容器初始化。初始化过程包括:

  • 定位
  • 加载:加载过程最复杂,先将xml读取为Element然后在将Element转换为BeanDefinitions。里面还有好多逻辑
  • 注册:注册比较简单,加载完毕后生成BeanDefinitionHolder对象,这个对象持有beanName和BeanDef所以直接get到然后放到Map结构中

最后将xml解析为BeanDefinition对象,放到map中,当调用getBean()执行时就会

  • 实例化
  • 依赖注入
public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            //调用容器准备刷新方法,获取容器的当前时间,同时给容器设置同步标识
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            //告诉子类启动refreshBeanFactory方法,Bean定义资源文件的载入从子类的refreshBeanFactory()方法启动
            /**
             * 1.AbstractRefreshableApplicationContext.refreshBeanFactory这个方法里面就是构造BeanFactory
             * 2.然后调用AbstractRefreshableApplicationContext.getBeanFactory赋值给ConfigurableListableBeanFactory
             * 3.返回return这个BeanFactory
             */
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            //为BeanFactory配置容器特性,例如类加载器,事件处理器等
            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();
            }
        }
    }

上面refresh方法实现的代码ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();这个就是创建IOC容器的方法。所以继续看这个方法的代码

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        //采用委派模式,父类提供接口,子类提供实现
        //创建BeanFactory的方法。
        refreshBeanFactory();

        //创建好BeanFactory之后,通过getBeanFactory获得方法
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }

调用父类AbstractRefreshableApplicationContext.refreshBeanFactory()创建容器。然后调用父类AbstractRefreshableApplicationContext.getBeanFactory()获得创建的IOC容器,并将这个IOC容器返回出去。下面是refreshBeanFactory代码第一部分是判断容器是否存在如果存在则销毁容器,重新创建。

protected final void refreshBeanFactory() throws BeansException {
        //判断是否已经存在IOC容器,如果存在,则销毁
        /**
         * hasBeanFactory()在判断AbstractRefreshableApplicationContext里面的成员变量beanFactory如果不是空,则需要销毁IOC容器
         */
        if (hasBeanFactory()) {
            //主要就是清除map。IOC的容器就是一个Map
            destroyBeans();
            //将BeanFactory=null
            closeBeanFactory();
        }
        try {
            //创建IOC容器,这个时候的beanFacotr仅仅只是new一下,容器里面还没有东西
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            //对IOC容器进行定制化,如设置启动参数,开启注解的自动装配等等
            customizeBeanFactory(beanFactory);

            //调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的loadBeanDefinitions,具体的实现调用子类容器
            //使用子类AbstractXmlApplicationContext来实现
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

从上面的代码可以知道spring实例了一个DefaultListableBeanFactory给用户使用。在DefaultListableBeanFactory beanFactory = createBeanFactory();里面只是new了一个容器,当时容器里面什么都没有真正填充容器的是loadBeanDefinitions(beanFactory)。

//调用AbstractXmlApplicationContext.loadBeanDefinitions这里采用了委派模式,自己不做事,交给子类做事
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
        //创建XmlBeanDefinitionReader,即Bean的读取器,并通过回调设置到容器beanFactory里面(目前beanFactory仅仅只是new了一个对象)容器使用这个读取器去读取Bean定义资源
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context's
        // resource loading environment.
        //为Bean读取器设置Spring资源加载器,AbstractXmlApplicationContext的父类AbstractApplicationContext 继承了 DefaultResourceLoader,因此容器也是一个Bean读取器
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);

        //为Bean读取器设置SAX xml解析器
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // then proceed with actually loading the bean definitions.
        //当Bean读取器读取Bean定义的xml资源文件时,启用xml校验机制,此处仅仅是设置了校验标志位:设置true
        initBeanDefinitionReader(beanDefinitionReader);

        //Bean读取器真正实现加载的方法
        loadBeanDefinitions(beanDefinitionReader);
    }

下面关于loadBeanDefinitions的层次很深,需要认真跟踪。

//AbstractXmlApplicationContext.loadBeanDefinitions
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        //获取Bean定义资源的定位
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            //xml Bean读取器调用父类AbstractBeanDefinitionReader读取定位的Bean定义资源
            reader.loadBeanDefinitions(configResources);
        }
        //采用委派模式,调用子类的获取Bean定义资源定位的方法,该方法在ClassPathXmlApplicationContext中实现
        //如果子类种获取的Bean定义资源定位为空,则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }

上面将资源定位到,调用XML读取器解析xml。调用XmlBeanDefinitionReader.loadBeanDefinitions()继续解析xml在spring里面如果某个方法以do开头那么这个方法就是真正做事的方法,其他方法都是套路,不停的调用调用而已看到下面方法

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

        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。这个方法里面首先将xml文件流解析为Document对象。

Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);

继续进入registerBeanDefinitions

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        //创建DefaultBeanDefinitionDocumentReader对象,这个对象里面存放就是bean alias import resource等等
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();

        //前面已经将XML文件内容转换为Document对象。
        //下面方法是将Document对象转成Spring里面的BeanDefinition对象
        //DefaultBeanDefinitionDocumentReader类里面的方法
        //并且将BeanDefinition注册到IOC容器中
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

上面registerBeanDefinitions中主要就是documentReader.registerBeanDefinitions(doc, createReaderContext(resource));将Document对象转成BeanDefinitions对象。继续进入这个方法。找到DefaultBeanDefinitionDocumentReader.registerBeanDefinitions方法。(马上就可以看到曙光了)

    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        logger.debug("Loading bean definitions");
        Element root = doc.getDocumentElement();
        //从Document里面获得Element的根元素开始解析。
        //以do开头的方法就是具体做事的方法
        doRegisterBeanDefinitions(root);
    }

继续看doRegisterBeanDefinitions方法

protected void doRegisterBeanDefinitions(Element root) {
        BeanDefinitionParserDelegate parent = this.delegate;
        //创建BeanDefinitionParserDelegate对象。这个对象就是解析Document对象中的数据。是要生成BeanDefinition的处理对象。在下面创建对象的时候已经将配置文件中<beans>里面的默认熟悉解析出来了
        /**
         * 在<beans><beans/>里面主要定义了默认的属性如下
            default-lazy-init
            default-merge
            default-autowire
            default-dependency-check
            default-autowire-candidates
            default-init-method
            default-destroy-method
         */
        this.delegate = createDelegate(getReaderContext(), root, parent);

        //默认的命名空间,也就是
        /**
         *xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"
         */
        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;
                }
            }
        }

        preProcessXml(root);

        //处理配置文件
        parseBeanDefinitions(root, this.delegate);

        postProcessXml(root);

        this.delegate = parent;
    }

上面的方法首先创建BeanDefinitionParserDelegate,然后读取配置文件中配置的全局默认属性。紧接着处理命名空间。然后处理preProcessXml(root);这个方法是空的。真正处理配置的方法是parseBeanDefinitions(root, this.delegate);

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            //取出root下面的子节点。一个一个的bean
            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)) {
                        //普通类型,则开始将Element转换成BeanDefinitions。下面的方法也区分是什么类型:import;alias;bean;beans
                        //一般的spring配置文件根目录只包含上面四种情况,所以下面的方法分别处理
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }

上面方法中从node节点中取出所有子节点,如果是普通的类型则开始解析parseDefaultElement(ele, delegate);

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        //处理import
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            importBeanDefinitionResource(ele);
        }
        //处理alias。在SimpleAliasRegistry对象中有一个map结构,将name和alias保存到map里面
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            processAliasRegistration(ele);
        }
        //处理bean
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            processBeanDefinition(ele, delegate);
        }
        //处理beans
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            //递归调用
            doRegisterBeanDefinitions(ele);
        }
    }

看到上面的方法心里终于放下心了,已经找到调用真正真正处理的地方了。直接进入处理Bean的地方

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        //将Element转成BeanDefinition。然后将BeanDefinition和BeanName交给BeanDefinitionHolder持有
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // Register the final decorated instance.
                //将BeanDefinition注册到IOC容器中
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

上面代码中BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);就是处理Element的方法,将Element转化成BeanDefinitionsHolder这个对象里面持有beanName和BeanDefinitions。然后就是注册过程。注册过程简单,调用BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());内部就是将beanName和BeanDefinitions关联起来

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

        // Register bean definition under primary name.
        String beanName = definitionHolder.getBeanName();
        //注册,将beanName和BeanDefinitions放到map中。使用的类:DefaultListableBeanFactory
        //主要有一下数据:
        // beanDefinitionMap:beanName作为key,BeanDefinitions作为value
        //List<String> beanDefinitionNames:list保存beanName
        //private volatile Set<String> manualSingletonNames保存单例的名字
        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);
            }
        }
    }

上面已经将xml文件注册成了BeanDefinitions对象并用键值对的方式保存到Map中。下面就是依赖注入的过程。当调用getBean()方法时就会触发依赖注入。在spring源码中经常看到N多个重载方法,一般都是有一个最全参数的重载方法,然后其他方法都是有默认值的调用这个最全参数的方法。在getBean中同样是这样设计的。可以找到getBean的入口方法:AbstractApplicationContext.getBean(String name)所有的重载方法getBean最后都是doGetBean()。代码如下AbstractBeanFactory.doGetBean

protected <T> T doGetBean(
            final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
            throws BeansException {
        //1.如果是FactoryBean这种Bean都是以&开头。所以需要去掉&
        //2.如果name的别名,则需要在SimpleAliasRegistry里面进行判断获取的真正的那么
        final String beanName = transformedBeanName(name);
        Object bean;

        // Eagerly check singleton cache for manually registered singletons.
        //从缓存中获取对象,避免重复创建
        Object sharedInstance = getSingleton(beanName);
        System.out.println(sharedInstance);
        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 + "'");
                }
            }
            /*这里 的 getObjectForBeanInstance 完成 的 是 FactoryBean 的 相关 处理,
            以 取得 FactoryBean 的 生产 结果, BeanFactory 和 FactoryBean 的 区别 已经 在前面 讲过, 这个 过程 在后面 还会 详细 地 分析*/
            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);
            }

            // Check if bean definition exists in this factory.
            /*
            这里 对 IoC 容器 中的 BeanDefintion 是否 存在 进行检查,
            检查 是否 能在 当前 的 BeanFactory 中 取得 需要 的 Bean。
            如果 在 当前 的 工厂 中 取 不到, 则 到 双亲 BeanFactory 中 去取;
            如果 当前 的 双亲 工厂 取 不到, 那就 顺着 双亲 BeanFactory 链 一直 向上 查找*/
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // Not found -> check parent.
                String nameToLookup = originalBeanName(name);
                if (args != null) {
                    // Delegation to parent with explicit args.
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {
                    // No args -> delegate to standard getBean method.
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }

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

            try {
                //通过beanName获得BeanDefinition对象  //这里 根据 Bean 的 名字 取得 BeanDefinition
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);

                // Guarantee initialization of beans that the current bean depends on.
                //检查bean配置是否设置了depend-on属性。即实例A需要先实例B
                //获取 当前 Bean 的 所有 依赖 Bean, 这样 会 触发 getBean 的 递归 调用, 直到 取 到 一个 没有
                // 任何 依赖 的 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);
                        }
                    }
                }
                /*这里 通过 调用 createBean 方法 创建 Singleton bean 的 实例, 这里 有一个 回 调 函数 getObject, 会在 getSingleton 中 调用 ObjectFactory 的 createBean*/

                // Create bean instance.
                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;
            }
        }

        // Check if required type matches the type of the actual bean instance.
        // 这里 对 创建 的 Bean 进行 类型 检查, 如果 没有 问题, 就 返回 这个 新 创建 的 Bean, 这个 Bean 已经 //是 包含 了 依赖 关系 的 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;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容