Spring读取Bean的过程

本文详细解析了Spring中Bean的加载过程,从缓存获取到实例化,涉及单例、原型bean的创建,循环依赖的处理,以及FactoryBean的应用。核心步骤包括:检查别名、从singletonCache获取bean、实例化bean、处理循环依赖、调用父BeanFactory、创建bean、处理依赖、转换对象类型等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring中Bean加载的过程是一个关键的步骤。这个过程主要是通过BeanFactoyr中的getBean方法来实现的。具体的方法是在AbstractBeanFactory方法中实现的。getBean方法主要有两个功能,首先是去缓存中读取bean,如果没有就实例化这个bean,实例化bean的过程是一个将GenericBeanDefinition转变为一个正式的bean的过程。
具体实现的方法是:

protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)

Spring代码中有个特点是所有的具体执行的代码都是以do 开头。

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 {
            // 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.
            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 {
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);

                // Guarantee initialization of beans that the current bean depends on.
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        registerDependentBean(dep, beanName);
                        getBean(dep);
                    }
                }

                // 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.
        if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
            try {
                return getTypeConverter().convertIfNecessary(bean, requiredType);
            }
            catch (TypeMismatchException ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Failed to convert bean '" + name + "' to required type '" +
                            ClassUtils.getQualifiedName(requiredType) + "'", ex);
                }
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        }
        return (T) bean;
    }

以上这段代码就是Spring中bean加载的过程。
第一步:
将beanName转变为正在的beanName原因是Spring中的aliasName的特性。Spring中内部维护了一个aliasBeanName和beanName之间的映射。

第二步:
先从singletonCache中获取到对应的bean。这个方法是DefaultSingletonBeanRegistry.getSingleton(String beanName)中实现的。
这个过程可以做一个简单的介绍:

1.从存放完全生成了的单例对象的singletonObjects中获取完全生成的bean。
2.如果为空判断当前的bean是否正在创建。主要是通过判断singletonBeanInCreation是否包含了这个beanName
3.如果正在创建,那么从earlySingletonObjects中获取到对应的Object。(这个Object是一个被创建,但是还没有被赋值的。可以理解为一个对象的引用
4.如果Obejct的应用还没有创建,如果允许循环依赖,就从singletonFactorys中获取到ObjectFactory中的对象。ObjectFactory可以认为是一个工厂方法,主要主要用来实例化bean。
5.如果ObejctFactory不为空,这个时候从ObjectFactory中获取到对象,先将对象添加到earlySingletonObjects中,同时将对应的ObjectFactory从SingletonFactorys中移除。这个过程完成了ObjectFactory向earlySingletonBean的转变。

Spring中bean实例化的过程主要是这样几个过程:

RootBeanDefinition --> ObjectFactory  --> earlySingeltonBean  --> Obeject

为什么会有这么复杂执行过程主要是为了解决Spring中循环依赖解决方法小结
第三步:如果获取了bean成功,这个时候需要判断一下这个实例是普通的Object还是一个FactoryBean。然后根据具体的情况获取到想要的bean。FactoryBean是如何实现的请见FactoyrBean小结

前面如果都失败了,说明这个bean对象并没有被缓存,就需要实例化bean了。

第四步:判断当前bean是否是一个prototype类型的,如果是就用AbstractBeanFactory中prototypesCurrentlyInCreation判断是否有循环依赖。主要是prototypesCurrentlyInCreation中记录了当前线程中正在创建的beanName信息,如果在创建当前bean的时候发现之前已经有一个相同的bean也在创建,这个时候就会有循环依赖的问题了。直接报错。

第五步:调用父BeanFactory中的getBean方法。这个过程和JVM中ClassLoader中双亲委派是一样的。
第六步:标记开始创建
具体实现的步骤如下:

1.将mergedBeanDefinitions中对应的RootBeanDefinition删除.
2.将当前bean添加到alreadyCreated 表示正在创建
这里有了一个doublecheck来保证线程安全。

第七步:
根据当前beanName获取到对应的GenericBeanDefinition,同时将这个对象转变为一个RootBeanDefinition对象,同时判断当前的RootBeanDefiniton是否是一个抽象类,如果是就抛异常。具体Spring中如何处理基础类的请看Spring中基础bean实现小结

第八步:
获取当前bean对应的depend的信息,如果出现循环依赖,那么就抛出异常。具体请看Spring中是如何处理循环dependOn的

以下就开始十里荷花对象:

第九步骤:判断如果是一个单例对象
就调用DefaultSingletonBeanRegistry.getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法来实例化当前的单例对象了。
其中ObjectFactory中getObject方法是调用了createBean(String beanName, RootBeanDefinition mbd, Object[] args)方法来实例化对象。
其中 createBean(String beanName, RootBeanDefinition mbd, Object[] args) 方法是当前系统中的关键。
具体如何创建的请看Spring中单例对象的创建小结

第十步:判断当前对象是一个prototype类型
创建一个单例prototype类型的对象。Spring创建prototype类型bean小结
第十一步:如果是其他类型的bean。调用对应类型的构造器。Spring中是如何创建其他Scope对象小结

第十四步:
将当前的object转变为想要的类型的对象。具体请看Spring中类型转变小结

总结:
Spring中doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) 简单描述首先从缓存中获取到对应的对象,如果就根据不同的scope实例化bean。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值