`

Spring源码解析-bean的加载

 
阅读更多

我们先看一道面试经常会问到的问题:spring的bean在什么时候实例化? ——第一:如果你使用BeanFactory,如XmlBeanFactory作为Spring Bean的工厂类,则所有的bean都是在第一次使用该bean的时候实例化 。第二:如果你使用ApplicationContext作为Spring Bean的工厂类,则又分为以下几种情况: 

       1.如果bean的scope是singleton的,并且lazy-init为false(默认是false,所以可以不用设置),则ApplicationContext启动的时候就实例化该bean,并且将实例化的bean放在一个线程安全的 ConcurrentHashMap 结构的缓存中,下次再使用该Bean的时候,直接从这个缓存中取 。

        2.如果bean的scope是singleton的,并且lazy-init为true,则该bean的实例化是在第一次使用该bean的时候进行实例化 。

       3.如果bean的scope是prototype的,则该bean的实例化是在第一次使用该Bean的时候进行实例化 。

ClassPathXmlApplicationContext有几个重载的构造函数最终都会调用父类AbstractApplicationContext的reflash方法,reflash方法在前文有介绍,作用是创建加载Spring容器配置。AbstractApplicationContext也有getBean方法:

AbstractApplicationContext下的代码:
public Object getBean(String name)throws BeansException {
        //Bean的获取外部容器交给了内部容器
        return getBeanFactory().getBean(name);
}

内部容器由DefaultListableBeanFactory承当,但真实的getBean方法实现是由其父类AbstractBeanFactory实现的,AbstractBeanFactory类同样实现了BeanFactory接口的方法,它有四个重载的getBean方法,不管哪一个都会去调用doGetBean方法:

                

                

那么doGetBean里干了什么事情呢?

protected <T> T doGetBean(
			final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException { 
//bean name处理,去除FactoryBean前缀等  
     final String beanName = transformedBeanName(name);  
     Object bean = null;  
  
//先从singleton缓存中查看是否已经实例化过该Bean,根据是否有缓存分为两个分支分别处理  
    Object sharedInstance = getSingleton(beanName);  
    if (sharedInstance != null && args == null) {  
// 分支一,若缓存中获取到了并且该BeanDefinition信息表明该bean是singleton的,直接将获取到的缓存Bean  
//(有可能是半成品)交给getObjectForBeanInstance处理  
 /*.........省略logger部分代码............*/  
//调用getObjectForBeanInstance处理  
     bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);  
    }else {  
// 分之二:没有缓存,则需要从头实例化该bean  
            // We're assumably within a circular reference.  
      if (isPrototypeCurrentlyInCreation(beanName)) {   
           throw new BeanCurrentlyInCreationException(beanName);}  
  
// 检查BeanDefinition是否在当前工厂或父工厂  
            BeanFactory parentBeanFactory = getParentBeanFactory();  
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {  
                // Not found -> check parent.  
                String nameToLookup = originalBeanName(name);  
                if (args != null) {  
// 父工厂getBean  
                    return parentBeanFactory.getBean(nameToLookup, args);  
                }  
                else {  
                    // No args -> delegate to standard getBean method.  
                    return parentBeanFactory.getBean(nameToLookup, requiredType);  
                }  
            }  
//将bean加入“正在创建”的集合,完成后会remove,对应afterSingletonCreation/afterPrototypeCreation方法  
            if (!typeCheckOnly) {  
                markBeanAsCreated(beanName);  
            }  
  
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);  
            checkMergedBeanDefinition(mbd, beanName, args);  
  
// 解决依赖关系,将依赖的bean提前实例化  
            String[] dependsOn = mbd.getDependsOn();  
            if (dependsOn != null) {  
                for (int i = 0; i < dependsOn.length; i++) {  
                    String dependsOnBean = dependsOn[i];  
                    getBean(dependsOnBean);  
                    registerDependentBean(dependsOnBean, beanName);  
                }  
            }  
  
// 这里又需要根据bean的类型分为三种情况:singleton、prototype、request/session  
            if (mbd.isSingleton()) {  
                           //通过自定义ObjectFactory实例化Bean,此结果可能是半成品(是FactoryBean等)  
                sharedInstance = getSingleton(beanName, new ObjectFactory() {  
                    public Object getObject()throws BeansException {  
                        try {  
                          //真正实例化装配的逻辑在createBean方法中  
                            return createBean(beanName, mbd, args);  
                        }  
                        catch (BeansException ex) {   
                            destroySingleton(beanName);  
                            throw ex;  
                        }  
                    }  
                });  
                        //上一步半成品的Bean交给getObjectForBeanInstance方法处理  
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);  
            }  
  
            else if (mbd.isPrototype()) {  
                Object prototypeInstance = null;  
                try {  
                    beforePrototypeCreation(beanName);  
                     //真正实例化装配的逻辑在createBean方法中  
                    prototypeInstance = createBean(beanName, mbd, args);  
                }  
                finally {  
                    afterPrototypeCreation(beanName);  
                }  
                    //上一步半成品的Bean交给getObjectForBeanInstance方法处理  
               bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);  
            }  
  
            else {  
                            //request、session 的bean  
                String scopeName = mbd.getScope();  
                final Scope scope = (Scope) this.scopes.get(scopeName);  
                if (scope == null) {  
        throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");  
                }  
                try {  
                    Object scopedInstance = scope.get(beanName, new ObjectFactory() {  
                        public Object getObject()throws BeansException {  
                            beforePrototypeCreation(beanName);  
                            try {  
                         //真正实例化装配的逻辑在createBean方法中  
                                return createBean(beanName, mbd, args);  
                            }  
                            finally {  
                                afterPrototypeCreation(beanName);  
                            }  
                        }  
                    });  
                       //上一步半成品的Bean交给getObjectForBeanInstance方法处理  
                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);  
                }  
            }  
        }  
   
        if (requiredType != null && bean != null &&  
                              !requiredType.isAssignableFrom(bean.getClass())) {  
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());  
        }  
        return bean;  
    }  

    bean的加载经历了一个复杂的过程,上面代码主要做了以下几件事(此段摘抄自《spring源码深度解析》):

        1.转换对应的beanName。如果name=“&aa”的,会去除&符号。或者<bean>标签带有alias(别名的意思),则取alias所表示最终的beanName。

         2.尝试从缓存中加载单例bean。如果加载不成功,会再次尝试从singletonFactories中加载。

        3.bean的实例化。假如我们需要对工厂bean进行处理,那么这里得到的其实是工厂bean 的初始状态。真正干活的则是getObjectForBeanInstance定义factory-method方法返回的bean。

        4.原型模式的依赖检查。如果A类有B的属性,B中有A的属性,则会产生循环依赖。spring如何解决循环依赖问题

        5.将存储的Xml配置文件的GernericBeanDefinition转换为RootBeanDefinition。前文提到的用于承载属性的BeanDefinition有三个实现,GernericBeanDefinition,RootBeanDefinition和ChildBeanDefinition,如果父类bean不为空的话,这里会把所有的属性一并合并父类属性,因为后续所有的Bean都是针对RootBeanDefinition的。

        6.寻找依赖。在初始化一个bean的时候,会首先初始化这个bean所对应的依赖。

        7.根据不同的scope创建bean。scope属性默认是singleton,还有prototype、request等。

        8.类型转换。如果bean是个String,而requiredType传入了Integer,然后返回bean,加载结束。

其中,最重要的步骤是(7),spring的常用特性都在那里实现.

分享到:
评论

相关推荐

    官方原版源码spring-framework-5.1.4.RELEASE.zip

    《Spring Framework 5.1.4源码深度解析》 Spring Framework是Java开发中的核心框架,它为构建高质量的企业级应用提供了全面的支持。5.1.4版本是Spring的重要里程碑,引入了诸多新特性和改进,旨在提升性能、增强可...

    官方源码 spring-framework-5.2.15.RELEASE.zip

    《Spring Framework 5.2.15.RELEASE 源码深度解析》 Spring Framework作为Java领域中最受欢迎的开源框架之一,它的每一个版本都备受关注。5.2.15.RELEASE是Spring Framework的一个稳定版本,它包含了丰富的特性和...

    官方原版源码spring-framework-4.3.25.RELEASE.zip

    研究Spring源码能帮助开发者提升对Java和软件设计的理解,学习最佳实践,提高代码质量和可维护性。同时,对于解决框架使用中的问题,或自定义扩展Spring功能,源码学习至关重要。 7. **未来发展趋势** 虽然Spring...

    spring源码解读-地址.txt

    根据提供的文件信息,本次解读将围绕Spring框架的核心概念与源码分析进行展开。Spring框架作为Java企业级开发中不可或缺的一部分,其源码的学习对于深入...希望以上内容能够为大家学习Spring源码提供一定的参考和帮助。

    官方原版源码spring-framework-5.1.9.RELEASE.zip

    《Spring Framework 5.1.9.RELEASE源码解析》 Spring Framework作为Java开发领域中的核心框架,一直以来都是开发者们关注的焦点。这次我们聚焦于官方原版源码spring-framework-5.1.9.RELEASE,这个版本包含了完整的...

    springBean加载过程源码解析文档,附有代码类名和行数

    Spring Bean 加载过程源码解析文档 Spring Bean 加载过程是 Spring 框架中最核心的部分之一,涉及到 ApplicationContext 的初始化、Bean 的加载和注册等过程。在 Spring Boot 应用程序中,SpringApplication 负责...

    Spring源码深度解析第二版

    Spring源码深度解析第二版 Spring是一款广泛应用于Java企业级应用程序的开源框架,旨在简化Java应用程序的开发和部署。Spring框架的核心主要包括了IoC容器、AOP、MVC框架等模块。 第1章 Spring整体架构和环境搭建 ...

    spring源码合集spring源码合集

    7. **Bean生命周期源码解析**:"05-Spring之Bean生命周期源码解析下-周瑜"将详细阐述Bean从创建到销毁的整个过程,包括初始化、后置处理、正常运行和销毁等阶段,使我们能更好地控制和管理Bean的状态。 8. **模拟...

    spring-framework-1.0-m1.zip源码

    《Spring框架1.0源码解析》 Spring框架,作为Java企业级应用开发的重要支柱,自2003年发布以来,已经历了多个版本的迭代,为开发者提供了丰富的功能和强大的支持。本文将深入探讨Spring 1.0源码,帮助读者理解其...

    官方原版源码 spring-framework-5.1.16.RELEASE.zip

    通过这些Schema,开发者可以编写出符合规范的配置文件,确保Spring能正确解析并加载配置。 在源码中,我们可以看到Spring对IoC(Inversion of Control)和DI(Dependency Injection)的卓越实现。IoC使得对象的创建...

    Spring Boot源码(spring-boot-2.6.2.zip)

    通过阅读这些核心组件的源码,我们可以深入理解Spring Boot是如何加载配置、启动应用、自动配置bean以及与其他Spring框架组件协作的。这将有助于提升我们的开发技能,解决潜在的问题,并且更好地优化Spring Boot应用...

    官方原版源码 spring-framework-5.2.9.RELEASE.zip

    1. **设计模式实践**:Spring源码中大量运用了工厂模式、单例模式、观察者模式等设计模式,学习源码能加深对设计模式的理解。 2. **性能优化**:通过对源码的学习,开发者可以了解Spring如何进行性能优化,如缓存、...

    spring-source-4.2.4源码

    《Spring框架4.2.4源码解析》 Spring框架是Java领域中广泛使用的轻量级开源框架,它以其模块化、松耦合的设计理念,为开发者提供了强大的企业级应用开发支持。本篇将深入探讨Spring 4.2.4版本的源码,通过分析各个...

    官方原版源码spring-framework-5.0.13.RELEASE.zip

    学习Spring源码能够帮助开发者: - **理解设计模式**:Spring大量使用了工厂模式、单例模式、代理模式等,深入源码有助于提升设计能力。 - **优化性能**:了解内部工作原理后,能更好地调整配置,优化应用性能。 - ...

    官方原版源码spring-framework-5.1.14.RELEASE.zip

    `BeanFactory`是Spring的最基础接口,用于管理和实例化bean,而`ApplicationContext`则在`BeanFactory`的基础上增加了对国际化、事件传播、资源加载等功能。`BeanDefinition`类定义了bean的元数据,如初始化方法、...

    spring源码-2022-08-14spring源码spring源码spring源码

    在2022年8月14日更新的Spring源码中,我们可以深入理解其设计理念和实现机制。 Spring框架的主要组成部分包括: 1. **核心容器**:这是Spring的基础,主要包括BeanFactory和ApplicationContext。BeanFactory负责...

    官方原版源码spring-framework-5.2.0.RELEASE.zip

    《Spring Framework 5.2.0源码深度解析》 Spring Framework是Java开发中的核心框架,它为构建高质量的企业级应用提供了全面的解决方案。官方原版源码spring-framework-5.2.0.RELEASE.zip包含了Spring 5.2.0版本的...

    Spring 源码分析(Bean的初始化)

    在解析Bean定义时,Spring会检查每个`&lt;bean&gt;`元素的`profile`属性,以确定当前环境是否应该处理该Bean。如果当前环境不接受`profile`指定的配置,那么这个Bean定义将被跳过,不会被解析和初始化。 接下来,Spring会...

    Spring源码分析.pdf

    这些方法都是 IOC 容器的基本行为,不关心 Bean 是如何定义和加载的,而是关心如何从 IOC 容器中获取 Bean 实例。 三、XmlBeanFactory XmlBeanFactory 是 Spring 提供的一种 IOC 容器的实现,它使用 Xml 文件来...

Global site tag (gtag.js) - Google Analytics