美文网首页SpringJava学习笔记Spring 学习笔记
【Spring源码学习】getBean (上)

【Spring源码学习】getBean (上)

作者: jwfy | 来源:发表于2018-01-20 17:57 被阅读35次

    学习和了解下spring中genBean函数具体的细节,其中包含了@value是如何和配置文件中的键值对关联上以及实例类的引用,这两部分打算分为上下两篇文章去详细介绍下。本文先介绍注解的值是如何和bean绑定并且填充的。

    接下来使用如下的小demo具体学习和了解下。

    public class Student {
    
        @Value("${name}")
        private String className;
        // 使用了@value注解,其中名称是name
        // 我们本章就是具体学习这个值是怎么样的方式,在什么时候注入进去的
    
        @Override
        public String toString() {
            return "Student{" +
                    "className='" + className + '\'' +
                    '}';
        }
    }
    
    public class Bootstrap {
    
        public static void main(String[] args){
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("context.xml");
    
            Student student = (Student)applicationContext.getBean("student");
            // getBean 入口
            System.out.println(student.toString());
        }
    }
    
    name = CS-2
    // 配置了name这个键值对,最后被填入Student类中
    

    在具体分析源码之前想象下如果我们是这个项目的开发者,我们需要考虑到哪些问题?

    • 现在已知的存在不同类型(scope)的bean被存储在容器中
    • 把获取的bean列表 循环一遍依次实例化、填充数据
    • 如果存在引用的则需要在实例化之前先行实例化引用类
    • 各种不同类型的容器,例如实例化好的,正在实例化的、正在被销毁的、已经消耗的
    • 填充数据这部分操作得支持@value等类似操作
    • 对外提供各种接口,便于用户可以自定义操作bean(例如BeanPostProcess)
    • 相互引用的情况,A引用B,B引用A该如何解决
    • 各种缓存容器,提高效率
    • 还有可能存在的并发问题

    接下来就看看具体的源码细节,在哪些地方会解决我们的疑惑

    AbstractBeanFactory 类的doGetBean函数

    protected <T> T doGetBean(
            final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
            throws BeansException {
    
        final String beanName = transformedBeanName(name);
        // 根据传入的bean的名称获取实际的beanName
        // 在这里其实就是看起是否为工厂bean还是bean工厂
        // 后续会有一篇重点分析下工厂bean和bean工厂的差异
        Object bean;
    
        // Eagerly check singleton cache for manually registered singletons.
        Object sharedInstance = getSingleton(beanName);
        // 从已经创建好的singletonObjects集合中验证是否已经存在该实例,已经存在了就没必要再调用生成了,不过需要注意到单例才是这样的,针对非单例的bean不是这样的
        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 {
            // 如果是当前处理的beanName已经在prototype容器中(同一个线程)被处理,则抛出异常
            // 看源码会发现是存储在ThreadLocal中的
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }
    
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // 如果父类存在而且当前需要处理的beanName还不在容器中
                // 需要由父类去调用生成相关的实例对象
                String nameToLookup = originalBeanName(name);
                // 这个originalBeanName就是去掉name中存在的多于的&,至多只保留一个&
                if (args != null) {
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {
                    // 没有参数
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }
    
            if (!typeCheckOnly) {
              // 传入的默认typeCheckOnly是false,把当前的beanName加入到准备实例化的alreadyCreated的容器中,存在并发的情况,源码使用了synchronized
                markBeanAsCreated(beanName);
            }
            
            // 上述步骤完成,对一个普通的bean而言就是加入到准备实例化的容器中
    
            try {
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                // 综合beanName本身映射的beandefinition和可能存在的父类beandefinition的属性
                // 存储到一个全新的对象RootBeanDefinition中
                checkMergedBeanDefinition(mbd, beanName, args);
    
                // 当前bean引用的其他bean,那很明显需要先实例化依赖的bean,再实例化本身
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        if (isDependent(beanName, dep)) {
                           // 如果当前beanName和dep存在相互依赖的情况,抛出异常
                           // 可是有个问题,不知道大家想到没有?
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        registerDependentBean(dep, beanName);
                        // 往当前的dependentBeanMap和dependenciesForBeanMap填入依赖关系
                        // 其中dependentBeanMap 是存储的当前对象依赖什么
                        // dependenciesForBeanMap 是被谁依赖被当前对象所依赖
                        getBean(dep);
                        // 每一个依赖的bean实例化
                    }
                }
                
                // 以上完成了bean的依赖问题,那就开始实例化本身了
    
                if (mbd.isSingleton()) {
                     // 是单例类型
                    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            try {
                              // 这个才是真正的创建bean对象的步骤!!!
                                return createBean(beanName, mbd, args);
                            }
                            catch (BeansException ex) {
                                destroySingleton(beanName);
                                throw ex;
                            }
                        }
                    });
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
    ....
    

    在上述代码中有提一个疑问,关于循环依赖的。循环依赖是A引用B的同时B也引用A,看上去形成了循环依赖,又如现场互斥一般死锁了,不过有一点需要注意到。

    • 构造器注入的时候才会真正形成循环依赖,会提示错误
    • 如果是setting注入则不会报错的,上面好像没说具体的依赖类型,只是有个mbd.getDependsOn

    回到过去看下如何取到getDependsOn数据的

    BeanDefinitionParseDelegate 文件

    
    public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, 
       String beanName,BeanDefinition containingBean, AbstractBeanDefinition bd) {
       .....
        if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
            String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
            // 支持多个数据,用逗号分开
            bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
        }
    
    

    很明显上述代码可以知道getDependsOn是bean的另一种属性DEPENDS_ON_ATTRIBUTE设置的值,这是一种比ref更强制性依赖的配置,从spring3.0开始有的,会提前初始化,看代码分析也确实是如何,但是和我们理解的循环依赖貌似不是同一件事情,这点后面再说。

    继续看如何生成object的

    AbstractAutowireCapableBeanFactory 文件

    protected Object createBean(String beanName, RootBeanDefinition mbd, 
            Object[] args) throws BeanCreationException {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;
        
        // 获得当前bean的的class,并且为了严格加载当前bean,生成一个新的对象mbdToUse
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }
    
        try {
            mbdToUse.prepareMethodOverrides();
            // 校验当前的bean使用overrides 重载方法是否合法(未重载则提示错误)
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }
    
        try {
            // 可以产生一个新的proxy代理去完成某些功能,也是一个接口
            // 需要去实现InstantiationAwareBeanPostProcessor类
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }
    
      // 来到了真正去创建一个普通的bean的地方了
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }
    

    上面的代码中介绍了InstantiationAwareBeanPostProcessor这个类,这个类也是BeanPostProcessor的一种,代码中这样描述这个功能的Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
            throws BeanCreationException {
    
        // 初始化一个bean的包装类(貌似框架级别的包装类都喜欢使用wrapper)
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
           // 生成bean实例
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        .....
    }
    
    
    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
        // 确认当前处理的bean是需要被处理的bean
        Class<?> beanClass = resolveBeanClass(mbd, beanName);
    
        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
        }
    
        if (mbd.getFactoryMethodName() != null)  {
           // 存在工厂方法,用工厂方法去实现实例化的功能
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }
    
        // Shortcut when re-creating the same bean...
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
        if (resolved) {
            if (autowireNecessary) {
                return autowireConstructor(beanName, mbd, null, null);
            }
            else {
                return instantiateBean(beanName, mbd);
            }
        }
    
        // SmartInstantiationAwareBeanPostProcessor
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
            return autowireConstructor(beanName, mbd, ctors, args);
        }
    
        // 实例化对象
        return instantiateBean(beanName, mbd);
    }
    
    

    至此已经生成了一个对象,但是其并没有相关属性,需要填充数据了,继续看doCreateBean方法

        BeanWrapper instanceWrapper = ......
        
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                    // 依旧是对beanpostprocessor接口的对外处理,接口是MergedBeanDefinitionPostProcessor
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }
    
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        // 已经缓存的实例用来解决循环引用
        if (earlySingletonExposure) {
            addSingletonFactory(beanName, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }
    
        // expose 对外输出的对象
        Object exposedObject = bean;
        try {
            populateBean(beanName, mbd, instanceWrapper);
            // 填充数据,这一步就是完成数据从配置文件到对象属性的设置
            if (exposedObject != null) {
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }
        
    

    如下图,最后是使用了AutowireAnnotationBeanPostProcessor 类去实现指的注入,圈住的地方恰好可以把值"CS-2"塞入"className"中

    image.png

    最后可能需要对获取到的object转一下格式,就完成了一整个的getBean的操作。

    在这里有一点需要注意到,在解析xml生成beandefinition和调用getBean之间并没有绝对的顺序之分,并不是解析xml完成,再去生成对应的实例的,在解析的时候如果需要具体的实例,则会立即调用getBean

    上面提的几个问题有些答案或许已经清楚了还有些可能不是非常清楚,下一篇文章再从比较宏观的角度出发去了解下getBean是如何解决各种问题的以及注解的值具体是如何被挂载上去的。

    相关文章

      网友评论

        本文标题:【Spring源码学习】getBean (上)

        本文链接:https://www.haomeiwen.com/subject/mwbtaxtx.html