Spring源码系列——依赖注入(二)createBean

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> Spring源码系列——依赖注入(二)createBean

在Spring源码系列:依赖注入(一)(AbstractBeanFactory-getBean)最后说道getBean是依赖注入的起点,bean的创建都是通过createBean来完成具体的创建的。createBean的具体实现是在AbstractAutowireCapableBeanFactory中的。本篇就捋一捋这个方法看下bean的创建过程。

这个方法是AbstractAutowireCapableBeanFactory这个类的中心方法,其作用就是创建一个bean实例,填充bean实例,后置处理等。

在createBean中主要做了三件事:

  • 判断需要创建的Bean是否可以实例化,这个类是否可以通过类装载器来载入
  • 是否配置了后置处理器相关处理(如果配置了则返回一个代理)
  • 创建Bean
  • 具体来看方法:

    
    protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;
        // Make sure bean class is actually resolved at this point, and
        // clone the bean definition in case of a dynamically resolved Class
        // which cannot be stored in the shared merged bean definition.
        //判断需要创建的Bean是否可以实例化,这个类是否可以通过类装载器来载入
        Class? resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }
    
        // Prepare method overrides.
        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            //异常:Validation of method overrides failed
        }
    
        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target 
            //bean instance.
            //是否配置了后置处理器相关处理(如果配置了则返回一个代理)
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            //异常:BeanPostProcessor before instantiation of bean failed
        }
        //创建Bean
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }
    

    从上面的代码中可以看到,创建bean是交给doCreateBean方法来创建的。继续看doCreateBean这个方法:
    (这里面涉及到一个BeanWrapper这个接口,小伙伴可以移步了解一下《Spring源码系列:BeanWrapper》)

    代码 1:

    
    // 用BeanWrapper来持有创建出来的Bean对象
    BeanWrapper instanceWrapper = null;
    //如果是单例的话,则先把缓存中的同名bean清除
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    //实际创建的交给createBeanInstance来完成,
    //bean的生成,这里会使用默认的类生成器,包装成BeanWrapperImpl类,
    //为了下面的populateBean方法的属性注入做准备  
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
    Class? beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
    mbd.resolvedTargetType = beanType;
    

    代码 2:

    允许后处理器修改合并的bean定义。

    
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
            //异常:Post-processing of merged bean definition failed
            }
            mbd.postProcessed = true;
        }
        }
    

    代码 3 :

    即使被BeanFactoryAware等生命周期接口触发,也要尽快地缓存singletons 以便能够解析循环引用。

    
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        if (logger.isDebugEnabled()) {
            logger.debug("Eagerly caching bean '" + beanName +
                    "' to allow for resolving potential circular references");
        }
        addSingletonFactory(beanName, new ObjectFactoryObject() {
            @Override
            public Object getObject() throws BeansException {
                return getEarlyBeanReference(beanName, mbd, bean);
            }
        });
    }
    

    代码 4:

    这里是对bean的初始化的地方,一般情况下依赖注入就在这里发生;这个exposedObject变量保存的是在初始化处理完以后返回的作为依赖注入完成之后的bean。

    
    // Initialize the bean instance.
    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 {
        //异常:Initialization of bean failed
        }
    }
    

    代码 5:

    这里是注册bean

    
    try {
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        //异常处理
    }
    //返回结果
    return exposedObject;
    

    上面的5个代码段均是doCreateBean中的处理逻辑,有兴趣的小伙伴可以自行查阅源码。从上面的代码中我们依然没有得到具体创建的过程,因为在doCreateBean中又依赖: createBeanInstance populateBean两个方法。

    createBeanInstance中生成了Bean所包含的java对象。来看是怎么生成的:

    
    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
        // 确保bean类实际上已经解析过了,可以实例化
        Class? beanClass = resolveBeanClass(mbd, beanName);
    
        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            //异常:Bean class isn't public, and non-public access not allowed:beanName
        }
         //1. 使用工厂方法来进行bean的实例化
        if (mbd.getFactoryMethodName() != null)  {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }
    
        // 重新创建相同的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);
            }
        }
    
        // 2.需要确定构造函数...,使用构造函数进行bean实例化
        Constructor?[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
            return autowireConstructor(beanName, mbd, ctors, args);
        }
    
        //3.没有特殊的处理:只需使用无参数构造函数。(默认构造函数)
        return instantiateBean(beanName, mbd);
    }
    

    从上面这段代码可以看出,对象的生成有许多不同的方式,有通过工厂的,也有通过容器的autowire特性生成的。当然这些生成方式都是由相关的BeanDefinition来指定的。

    Spring中配置Bean的方式我们常用的一种是通过xml文件来配置,还有就是通过注解的方式来配置

  • **demo1**
  • 
    bean id="user" class="com.glmapper.test.User"
      property name="name" value="glmapper"/property       
    /bean
    

    这种方式,通过class提供的权限定名,spring就可以利用反射机制创建这个bean。

  • **demo2**
  • 
    bean id="user" class="com.glmapper.test.UserFactory" factory-method="getUser"
        constructor-arg value="glmapper"/constructor-arg           
    /bean
    

    这种是利用静态工厂方法来创建的,提供的class并非是类的权限定名, 而是静态工厂的全类名;除此之外还需要指定获取bean的方法(此处是getUser)和参数(参数是glmapper)。

  • **demo3**
  • 
    bean id="userFactory" class="com.glmapper.test.UserInstanceFactory"
        !--用一个集合来保存我当前的对象实例--
        property name="map"
            map
                entry key="user1"
                    bean class="com.glmapper.test.User"
                        property name="name" value="glmapper1"/property        
                    /bean
                /entry    
                entry key="user2"
                    bean class="com.glmapper.test.User"
                        property name="name" value="glmapper2"/property   
                    /bean
                /entry
            /map  
        /property
     /bean
     //实例1
     bean id="user1" factory-bean="userFactory" factory-method="getUserInstance"
        constructor-arg value="user1"/constructor-arg           
     /bean
    //实例2
     bean id="user2" factory-bean="userFactory" factory-method="getUserInstance"
        constructor-arg value="user2"/constructor-arg           
     /bean
    

    这种方式和静态工厂的区别在于我们需要先实例化一个工厂对象,然后才能使用这个工厂对象来创建我们的bean。getUserInstance通过key值来获取我们已经实例化好的对象(当然方式有很多,此处以map来举个例子)。 关于注解的和使用FactoryBean接口的这里就暂时不说,后期再聊

    OK,继续来分钟,上面说到的是以工厂方法创建bean,具体的源码有点长,这里就不放了,大概思路就如上面所提到的那几种方式。接下来看下常见的使用instantiateBean方式(使用它的默认构造函数)来构建bean的代码:

    
    protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
        try {
            Object beanInstance;
            final BeanFactory parent = this;
            //获取系统安全接口。
            //如果已经为当前应用程序建立了安全管理器,则返回该安全管理器; 
            //否则,返回null。
            if (System.getSecurityManager() != null) {
                beanInstance = AccessController.doPrivileged(new PrivilegedActionObject() {
                    @Override
                    public Object run() {
                        return getInstantiationStrategy().instantiate(mbd, beanName, parent);
                    }
                }, getAccessControlContext());
            }
            else {
                beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
            }
            BeanWrapper bw = new BeanWrapperImpl(beanInstance);
            initBeanWrapper(bw);
            return bw;
        }
        catch (Throwable ex) {
            //异常:Instantiation of bean failed
        }
    }
    

    可以看出,上面的创建都是通过:

    
    getInstantiationStrategy().instantiate(mbd, beanName, parent);
    

    这样一段代码来完成的,是的,这里已经快接近真相了。从语义上来分析,先是获取了一种策略,然后利用当前获取的策略再去执行实例化。OK,我们看下getInstantiationStrategy()拿到的是什么:

    
    //返回实例化策略用于创建bean实例。
    protected InstantiationStrategy getInstantiationStrategy() {
        return this.instantiationStrategy;
    }
    //默认的实例化测试是使用CGLIB代理
    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
    

    看到这里我们清楚了,默认构造函数的情况下,在spring中会使用Cglib来进行bean的实例化(关于cglib此处不再赘述)。我们看下CglibSubclassingInstantiationStrategy这个类的申明:

    
    public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy 
    

    它继承自SimpleInstantiationStrategy ,这个又是什么鬼呢?

    SimpleInstantiationStrategy是Spring用来生成Bean对象的默认类,在这个类中提供了两种实例化java对象的方法,一种是基于java自身反射机制的BeanUtils,还有一种就是基于Cglib

    如何创建的就不说了;到这里createBeanInstance就说完了(Bean已经创建了);但是仅仅是创建,spring还没有处理它们,比如说bean对象的属性,依赖关系等等。这些就是上面提到的另外一个方法populateBean;

    这个方法其实就做了一件事:使用bean定义中的属性值在给定的BeanWrapper中填充bean实例。分段来看:
    下面这段代码是先将BeanDefinition中设置的property值封装成PropertyValues,然后检测我们的BeanWrapper是否为Null,如果为null则抛出异常或者跳过当前空实例赋值阶段

    
    //获取到BeanDefinition中设置的property值,封装成PropertyValues
    PropertyValues pvs = mbd.getPropertyValues();
    if (bw == null) {
        if (!pvs.isEmpty()) {
        //异常:Cannot apply property values to null instance
        }
        else {
        // Skip property population phase for null instance.
            return;
        }
    }
    

    下面这段代码的意思是给任何InstantiationAwareBeanPostProcessors提供在设置属性之前修改bean状态的机会。

    
    boolean continueWithPropertyPopulation = true;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    continueWithPropertyPopulation = false;
                    break;
                }
            }
        }
    }
    
    if (!continueWithPropertyPopulation) {
        return;
    }
    

    下面就是对具体注入方式的处理:

    
    //处理autowire的注入;可以根据bean的名称和类型来注入
    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
        mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
    
        // 则根据名称添加基于自动装配的属性值。
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
    
        // 根据类型添加基于自动装配的属性值。
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
    
        pvs = newPvs;
    }
    

    两个判断条件,在满足的情况下做的处理分别是:

  • 在工厂将给定属性值应用到给定的bean后,对其进行后处理。 允许检查所有的依赖关系是否被满足,例如基于bean属性设置器上的“Required”注解。还允许替换要应用的属性值,通常通过创建基于原始PropertyValues的新MutablePropertyValues实例,添加或删除特定值。
  • 执行依赖性检查    
  • 
    //返回这个工厂是否拥有一个InstantiationAwareBeanPostProcessor
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    //返回依赖检查代码。
    boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
    
    if (hasInstAwareBpps || needsDepCheck) {
    //从给定的BeanWrapper中提取一组已过滤的PropertyDescriptors,
    //不包括在被忽略的依赖性接口上定义的被忽略的依赖类型或属性(译注)。
        PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        if (hasInstAwareBpps) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                    if (pvs == null) {
                        return;
                    }
                }
            }
        }
        if (needsDepCheck) {
            checkDependencies(beanName, mbd, filteredPds, pvs);
        }
    }
    

    最后是对属性进行注入:

    
    applyPropertyValues(beanName, mbd, bw, pvs);
    

    这个方法描述的是对属性进行解析然后注入的过程;先来分析下applyPropertyValues的申明:

    
    protected void applyPropertyValues(String beanName
    , BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs)
    
  • beanName bean名称
  • mbd 合并的bean definition
  • bw 包装目标对象的BeanWrapper
  • pvs 新的属性值
  • 代码分段来看:

  • 参数验证
  • 
    if (pvs == null || pvs.isEmpty()) {
        return;
    }
    
  • pvs参数处理
  • 
    if (pvs instanceof MutablePropertyValues) {
        mpvs = (MutablePropertyValues) pvs;
        if (mpvs.isConverted()) {
            // 使用预先转换后的值。
            try {
                bw.setPropertyValues(mpvs);
                return;
            }
            catch (BeansException ex) {
                //异常:Error setting property values
            }
        }
        original = mpvs.getPropertyValueList();
        }
        else {
        original = Arrays.asList(pvs.getPropertyValues());
        }
    
  • valueResolver来解析BeanDefinition
  • 
    BeanDefinitionValueResolver valueResolver = 
    new BeanDefinitionValueResolver(this, beanName, mbd, converter);
    
  • 为解析值创建一个副本,注入到bean中的是副本的数据
  • 
    // Create a deep copy, resolving any references for values.
    ListPropertyValue deepCopy = new ArrayListPropertyValue(original.size());
    
  • 遍历处理
  • 
    boolean resolveNecessary = false;
    for (PropertyValue pv : original) {
        //返回此持有者是否已经包含转换后的值(true),还是需要转换值(false)。
        if (pv.isConverted()) {
            deepCopy.add(pv);
        }   
        else {
            String propertyName = pv.getName();
            Object originalValue = pv.getValue();
            //看下面的注释resolveValueIfNecessary
            Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
            Object convertedValue = resolvedValue;
            boolean convertible = bw.isWritableProperty(propertyName) &&
                    !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
            if (convertible) {
                convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
            }
            // 可能将转换的值存储在合并的bean定义中,以避免为每个创建的bean实例重新转换。
            if (resolvedValue == originalValue) {
                if (convertible) {
                    pv.setConvertedValue(convertedValue);
                }
                deepCopy.add(pv);
            }
            else if (convertible && originalValue instanceof TypedStringValue &&
                    !((TypedStringValue) originalValue).isDynamic() &&
                    !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                pv.setConvertedValue(convertedValue);
                deepCopy.add(pv);
            }
            else {
                resolveNecessary = true;
                deepCopy.add(new PropertyValue(pv, convertedValue));
            }
        }
    }
    
  • resolveValueIfNecessary 给定一个PropertyValue,返回一个value,必要时解析对工厂中其他bean的引用。value可以是:
    • 一个BeanDefinition,它导致创建一个相应的新的bean实例。 Singleton标志和这样的"inner beans"的名字被忽略:内部beans是匿名原型。
    • RuntimeBeanReference(必须解析)
    • ManagedList
    • ManagedSet
    • ManagedMap
    • 一个普通的对象或null,在这种情况下,它是孤立的。
    • 给定一个PropertyValue,返回一个value,必要时解析对工厂中其他bean的引用。value可以是:

      下面这段代码时依赖注入发生的地方,其实际上是在BeanWrapperImpl中来完成。

      
      try {
          bw.setPropertyValues(new MutablePropertyValues(deepCopy));
      }
      catch (BeansException ex) {
          //异常:Error setting property values
      }
      

      上面说到spring是通过BeanDefinitionValueResolver来解析BeanDefinition的,然后再注入到property中,关于这个过程在下一篇中来说。

      欢迎关注微信公众号

      原文始发于微信公众号(glmapper工作室):

    本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

    本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

    原文链接:blog.ouyangsihai.cn >> Spring源码系列——依赖注入(二)createBean


     上一篇
    Spring源码系列——BeanDefinition载入(中) Spring源码系列——BeanDefinition载入(中)
    Web核心-Servlet Spring源码系列:启动过程 Spring源码系列:容器刷新 Spring源码系列:BeanFactory的创建 Spring源码系列:BeanDefinition源码解析 Spring源
    2021-04-05
    下一篇 
    Spring源码系列——依赖注入(三)-属性注入 Spring源码系列——依赖注入(三)-属性注入
    前面文章中对依赖注入的触发和bean的创建做了学习记录,本文将来记录一下bean的属性注入过程。Bean的属性注入发生在 BeanDefinitionValueResolver这个类中, BeanDefinitionValueResolve
    2021-04-05