转载

GetBean源码全面解读

前言

在上篇文章刨坑的过程中,顺便研究了一波spring源码,初始看的也是头晕,后面逐渐捋好了思路。个人感觉spring还是个大工程的,这篇文章解读的肯定也有自己理解不到位的部分,希望各位看官能多讨论讨论。最后会附上一副getBean方法的流程图,希望能打开大家看这部分源码的思路。(本文基于spring 5.1.2版本)

GetBean源码部分

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        //会包括解析别名等操作
        final String beanName = transformedBeanName(name);
        Object bean;

        // 先检查单例列表中是否已经注册了这个bean
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }
        else {
            // 检查bean是否并发被创建
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }
            // 检查是否在父类工厂中,逻辑和这个差不多,这里省略....

           //标记bean正在被创建
            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }
            try {
                //合并父类中的方法及属性,下面会细讲                      
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                //检查这个bean是否为抽象类
                checkMergedBeanDefinition(mbd, beanName, args);

                // 这里是为了保证获取的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 ex;
                        }
                    }
                }

                // 创建单例的bean,看下方的createBean方法
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            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, () -> {
                            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;
            }
        }

        // 检查需要的类型和实际传参类型是否一致. 这里省略....
        return (T) bean;
    }
复制代码

整个操作大概是以下几步:

  1. 获取实际的beanName,其中会处理带&号前缀的beanName,并解析别名。
  2. 检查单例列表中是否存在该beanName的bean,若存在则无需走下面的创建bean的流程。
  3. 若单例列表中并不存在此bean,则检查是否有并发创建。这里的判断只针对scope为prototype类型的bean。
  4. 检查bean是否存在于父类工厂中,若存在,则走父类工厂的getBean流程。向上委托,保证容器中只会存在一个同名的bean。
  5. 标记bean正在被创建。
  6. 如果有父类,这里会递归合并父类的方法以及属性。并会用自己重写的方法覆盖其父类的方法。合并完成并检查这个bean的是否是抽象类。
  7. 如果该bean上有注解@DependsOn,或者配置文件上配置有该属性,则需保证该bean的所有依赖需要先在容器内注册。
  8. 分单例和原型以及其他scope类型来创建bean。
  9. 检查需要的类型和生成的bean类型是否一致。
  10. 返回创建好的bean。

getSingleton源码部分(beanName,allowEarlyReference)

GetBean源码全面解读
  1. 这里的singletonObjects是一个缓存了beanName和bean的Map,若存在,直接返回。
  2. 不存在,则检查是否这个bean是否正在创建的过程中,先检查earlySingletonObjects这个容器,这个容器里面放着的是已经构造完成但是没有注入属性的对象,若存在,也会直接返回。
  3. 尝试着从singletonFactories中获取,然后调用getObject方法去获取对象。并将获取到的对象放到earlySingletonObjects容器中,然后从singletonFactories容器中移除。

这里这么设计是为了解决循环依赖的问题。若A依赖B,B依赖C,C又依赖A,这样三个bean就形成了一个环(这里只是针对set方法注入的bean,构造器注入还是会有循环依赖的问题而抛出异常的),spring会将创建的bean实例提前暴露在缓存中,一旦下一个bean创建的时候需要依赖上个bean,则直接使用ObjectFactory来获取bean。

这里举个生活中的例子阐述下:就拿建一个小区房来说,建房子是一个很复杂的工序,但是咱们只要把架子搭好,告诉大家这块地是用来建这个房子的就行。至于其他装修,家私等等东西都可以后面再进行补充。咱们不能搭架子的时候去放家具吧,这样整个都会乱套,也不符合常理。(这里房子的框架是咱们程序中的一个对象A,家具是另一个对象B,A依赖B,B依赖A)

循环依赖

相关的逻辑有用到以下代码段:

GetBean源码全面解读

每次singleton bean创造之前都会调用的方法,在singletonsCurrentlyInCreation容器中加入这个bean的beanName,标记这个bean正在创建中,供后期生成ObjectFactory。这里有个inCreationCheckExclusions容器,在这里我理解为属于该容器的bean必须要初始化完成才允许被获取。也就是说,添加进该容器后bean便不会允许早期的循环依赖了。

GetBean源码全面解读

上面的代码片段的调用在doCreateBean源码中(排在bean对象创建之后和属性注入之前),可以观察到要执行addSingletonFactory方法需要满足三个条件:

  • 这个bean是单例的,
  • 允许循环依赖,
  • 这个bean正在被创建的过程中。

在满足这三个条件的情况下,会在singletonFactories容器中缓存一个生成该bean的工厂,将其提前暴露出去。这里关注下 getEarlyBeanReference(beanName, mbd, bean) 这个方法,实际上ObjectFactory中getObject方法调用的也是这个方法。

getMergedBeanDefinition源码部分

看这部分之前,首先得明白BeanDefinition是用来干什么的,这个类会在整个源码解析过程中出现无数次。Spring把BeanDefinition定义成IOC容器的内部数据结构,实际上它也就是POJO对象在IOC容器中的抽象,通过这个对象,IOC容器能很方便的对Bean进行管理,包括利用它进行属性的注入等等…

protected RootBeanDefinition getMergedBeanDefinition(
            String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
            throws BeanDefinitionStoreException {

        synchronized (this.mergedBeanDefinitions) {
            RootBeanDefinition mbd = null;

            // 重新去获取一次,有可能该BeanDefinition已经生成
            if (containingBd == null) {
                mbd = this.mergedBeanDefinitions.get(beanName);
            }

            if (mbd == null) {
                if (bd.getParentName() == null) {
                    // 没有父类则深拷贝一个RootBeanDefinition
                    if (bd instanceof RootBeanDefinition) {
                        mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
                    }
                    else {
                        mbd = new RootBeanDefinition(bd);
                    }
                }
                else {
                    // 有父类则需要先获取父类的BeanDefinition,流程和获取子类的BeanDefinition一致
                    BeanDefinition pbd;
                    try {
                        String parentBeanName = transformedBeanName(bd.getParentName());
                        if (!beanName.equals(parentBeanName)) {
                            pbd = getMergedBeanDefinition(parentBeanName);
                        }
                        else {
                            BeanFactory parent = getParentBeanFactory();
                            if (parent instanceof ConfigurableBeanFactory) {
                                pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
                            }
                            else {
                                throw new NoSuchBeanDefinitionException(parentBeanName,
                                        "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                                        "': cannot be resolved without an AbstractBeanFactory parent");
                            }
                        }
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                                "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
                    }
                    //这里进行深拷贝,并将子类重写的方法和属性进行覆盖
                    mbd = new RootBeanDefinition(pbd);
                    mbd.overrideFrom(bd);
                }

                // 若前面没配置scope类型,这里设置为单例范围
                if (!StringUtils.hasLength(mbd.getScope())) {
                    mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
                }

                // 这里对内部类做了一些处理,若包含它的bean不是单例的,则该bean也将不会是单例的
                if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
                    mbd.setScope(containingBd.getScope());
                }

                // 将生产的BeanDefinition 缓存起来
                if (containingBd == null && isCacheBeanMetadata()) {
                    this.mergedBeanDefinitions.put(beanName, mbd);
                }
            }

            return mbd;
        }
    }
复制代码
  1. 在mergedBeanDefinitions同步的情况下再次读取缓存,防止该BeanDefinition已经被合并过了。
  2. 检查是否有父类,若有父类,则必须递归去合并BeanDefinition。
  3. 将子类重写后的方法覆盖到定义的BeanDefinition中。
  4. 设置scope类型。
  5. 将生成的BeanDefinition缓存起来。

registerDependentBean源码部分

GetBean源码全面解读

这一部分应该还是很容易理解的,这里面出现了两个Map,一个是 dependentBeanMap ,它主要用来装载键为beanName值为dependentBeanName的容器,另一个 dependenciesForBeanMap 是用来装载键为dependentBeanName值为beanName的容器,这样可以方便我们观察一个类需要组装哪些依赖,然后这个类同时是哪些类的依赖。

getSingleton源码部分(beanName,singletonFactory)

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "Bean name must not be null");
        synchronized (this.singletonObjects) {
//先去singletonObjects容器中去获取,能获取到就直接返回了
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
//调用destroySingletons方法singletonsCurrentlyInDestruction属性才会变成true
                if (this.singletonsCurrentlyInDestruction) {
                    throw new Exception("xx"));
                }
//这里会将beanName缓存到singletonsCurrentlyInCreation集合中
                beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet<>();
                }
                try {
        //这里会触发下面的createBean方法
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                }
                catch (IllegalStateException ex) {
                    // 如果是与此同时被创建了,则直接获取,如果能获取到值不为null,则正常返回。
                    //(注意这里捕获异常正常返回的话就不会走下面的addSingleton方法了。)
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        throw ex;
                    }
                }
                catch (BeanCreationException ex) {
                    if (recordSuppressedExceptions) {
                        for (Exception suppressedException : this.suppressedExceptions) {
                            ex.addRelatedCause(suppressedException);
                        }
                    }
                    throw ex;
                }
                finally {
                    if (recordSuppressedExceptions) {
                        this.suppressedExceptions = null;
                    }
//这里会将beanName从singletonsCurrentlyInCreation集合中移除
                    afterSingletonCreation(beanName);
                }
                if (newSingleton) {
//添加到singletonObjects和registeredSingletons缓存中,并从singletonFactories和earlySingletonObjects中移除
                    addSingleton(beanName, singletonObject);
                }
            }
            return singletonObject;
        }
    }
复制代码
  1. 直接去singletonObjects中获取,获取到了便直接返回。
  2. 获取不到,先将beanName缓存到singletonsCurrentlyInCreation集合中,作为标记表示该bean正在被创建的过程中。
  3. 触发createBean方法去创建bean,这里可以去看一下ObjectFactory这个接口工厂,这里是对getObject方法的一个回调(AbstractAutowireCapableBeanFactory中的createBean方法)。
  4. 创建bean的过程中在不出异常的情况下便会进行下图的操作后并返回,也就操作了几个容器的缓存而已。
    GetBean源码全面解读

createBean源码部分

这一块不是很复杂,复杂的地方在doCreateBean这个方法中。

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        RootBeanDefinition mbdToUse = mbd;

        // 要保证RootBeanDefinition的beanClass是存在的
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        // 这一块没什么研究,注解意思是(检查所有带有override的方法是否都是存在的)
        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
        }

        try {
            //这一块我猜测大概是看咱们自己有提供实例化的方法不,若有,则不会走下面的doCreateBean方法。
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
        }

        try {
            //创建bean的真正方法
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            }
            return beanInstance;
        }
        catch (Exception e){
           throw e;
        }
    }
复制代码

doCreateBean源码部分

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
// 创建这个bean,真正构建时有分两种情况,jdk反射和cglib动态代理
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        // 允许后置处理器来修改这个BeanDefinition
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                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) {
            if (logger.isTraceEnabled()) {
                logger.trace("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
//进行属性的注入,调用bean的set方法进行字段的初始化
            populateBean(beanName, mbd, instanceWrapper);
//进行一些初始化方法的调用,比如afterPropertiesSet等等。
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
        }

        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
//在出现循环依赖后,从earlySingletonObjects中获取的bean对象和initializeBean后
//的不一致,证明被后置处理器处理过了,前后bean不一致,需要抛出异常
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference, but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        // 注册bean的销毁方法
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }
复制代码

doCreateBean大概有以下步骤:

  1. 调用createBeanInstance方法初始化bean实例,这里不包括属性的注入。
  2. 调用合并bean的后置处理器修改这个bean的BeanDefinition的一些定义。即调用MergedBeanDefinitionPostProcessor的实现类的postProcessMergedBeanDefinition方法对BeanDefinition进行一些额外的处理。
  3. 为早期的循环依赖做准备,将包装了bean的工厂方法塞到singletonFactories中。
  4. 调用populateBean方法进行一些属性的注入。
  5. 执行initializeBean方法进行一些初始化方法的调用,例如:afterPropertiesSet方法的调用。与此同时,其后置处理器有可能对指定的bean进行增强。
  6. 如果出现了bean的增强,然后又有依赖它的类先生成,则需抛出异常。例如:对象A被增强了,得到A+对象,而此时对象B有依赖对象A,循环依赖时通过singletonFactories获取到的对象却是增强前的A对象,这时就会出现问题。如果不抛出异常,spring容器缓存的是A+对象,但是B引用的却是A,这样就会出现不可预测的问题。

instantiateBean源码

GetBean源码全面解读

这里是createBeanInstance方法中最终调用的方法,这里有三个流程:

  1. 进行对象的构造,这里关注下CglibSubclassingInstantiationStrategy这个策略类,有继承SimpleInstantiationStrategy类,调用其instantiate可以调用对象的构造器进行对象的初始化,在BeanDefinition属性MethodOverrides不存在时,可以用jdk的反射进行获取对象,否则则必须使用cglib动态代理。(这里的MethodOverrides的存在需要对象中某个方法用@Lookup注解修饰,或者XML定义中有 lookup-method属性,这一块的详情可以参考详情;)
  2. 用BeanWrapperImpl对生成的对象进行包装,并激活注册默认编辑器的属性。
  3. 注册默认的编辑器,然后将ConversionService这个类的引用设置到BeanWrapper对象上。ConversionService是用来进行类型转换的,里面的属性converters用一个map维护着各种类型的转换器。

populateBean源码部分

下面关注几个重点代码,省略了一些代码,可以自己去翻阅下:

    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        ......
        PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

        if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
            // 这里是根据bean名称进行依赖注入的
            if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
                autowireByName(beanName, mbd, bw, newPvs);
            }
            // 这里是根据bean的类型进行依赖注入的
            if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
                autowireByType(beanName, mbd, bw, newPvs);
            }
            pvs = newPvs;
        }
        ......
        if (pvs != null) {
//实际上注入属性值的方法,这里是populateBean方法的重点
            applyPropertyValues(beanName, mbd, bw, pvs);
        }
    }
复制代码

这里注释下applyPropertyValues的部分源码:

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
        MutablePropertyValues mpvs = null;
        List<PropertyValue> original;

        if (pvs instanceof MutablePropertyValues) {
            mpvs = (MutablePropertyValues) pvs;
            if (mpvs.isConverted()) {
                // 这里可以迅速返回。当这个PropertyValues对象中的值都是处理过后便可以触发。状态值会在下面几行代码设置。
                try {
                    bw.setPropertyValues(mpvs);
                    return;
                }
                catch (BeansException ex) {
                    throw new BeanCreationException(
                            mbd.getResourceDescription(), beanName, "Error setting property values", ex);
                }
            }
            original = mpvs.getPropertyValueList();
        }
        else {
            original = Arrays.asList(pvs.getPropertyValues());
        }

        TypeConverter converter = getCustomTypeConverter();
        if (converter == null) {
            converter = bw;
        }
        BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

        // 这里是个深拷贝,解析所有引用的值。
        List<PropertyValue> deepCopy = new ArrayList<>(original.size());
        boolean resolveNecessary = false;
        for (PropertyValue pv : original) {
            if (pv.isConverted()) {
                deepCopy.add(pv);
            }
            else {
                String propertyName = pv.getName();
                Object originalValue = pv.getValue();
//这里的resolveValueIfNecessary是一个需要关注的方法,有兴趣的小伙伴可以点进去看看,
//里面封装了针对各种类型的属性的解析,例如List,Map,Set等等类型。
                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);
                }
                //为了避免每次创建都去转换属性
                if (resolvedValue == originalValue) {
//这里的触发条件必须为该属性得是有写权限的,并且里面不能带有“.”和“[”这个符号,这里我的理解是
//teacher.name以及student[1].name这样的propertyName便不能触发这个条件
                    if (convertible) {
                        pv.setConvertedValue(convertedValue);
                    }
                    deepCopy.add(pv);
                }
                else if (convertible && originalValue instanceof TypedStringValue &&
                        !((TypedStringValue) originalValue).isDynamic() &&
                        !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
//这一块的条件比上一个多了几个,源值必须是string类型,且不能是动态的,并且不能是集合和数组中的任意一个。
                    pv.setConvertedValue(convertedValue);
                    deepCopy.add(pv);
                }
                else {
//条件在这里触发后就不会打开快捷返回的开关了
                    resolveNecessary = true;
                    deepCopy.add(new PropertyValue(pv, convertedValue));
                }
            }
        }
//设置converted状态值,供其组装属性时快捷返回。
        if (mpvs != null && !resolveNecessary) {
            mpvs.setConverted();
        }

        // 将我们深拷贝出来的值设置到包装类BeanWrapperImpl包装的对象上
        try {
            bw.setPropertyValues(new MutablePropertyValues(deepCopy));
        }
        catch (BeansException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Error setting property values", ex);
        }
    }
复制代码

setPropertyValues方法的源码最终调用的是AbstractNestablePropertyAccessor类的setPropertyValue方法,在这里BeanWrapperImpl是它的实现类,从名字上看也能猜出来这个类是个处理嵌套属性的访问器。

    public void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException {
        AbstractNestablePropertyAccessor nestedPa;
        try {
                  //这里可以解析嵌套的属性
            nestedPa = getPropertyAccessorForPropertyPath(propertyName);
        }
        catch (NotReadablePropertyException ex) {
            throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
                    "Nested property in path '" + propertyName + "' does not exist", ex);
        }
        //这里获取到了最终解析到的属性名
        PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
       //给最终解析到的属性名赋值操作
        nestedPa.setPropertyValue(tokens, new PropertyValue(propertyName, value));
    }
复制代码

上面有个getPropertyAccessorForPropertyPath方法,点进去会发现他会有个解析“.”和“[]”的方法getNestedPropertySeparatorIndex,它的作用我举个例子来说明一下:一个班级有多个学生,我想设置某个学生的名字,班级是个Class对象,里面有属性: private Student[] students 这里我想修改下student[2]的name属性,我就必须先用getStudent方法取出 Student[] 数组,然后再在 Student[] 数组中找到索引为2的Student,最后修改Student身上的name属性。(这一块不是很理解的可以参考下BeanWrapper 源码分析)

GetBean流程图

GetBean源码全面解读

End

原文  https://juejin.im/post/5c1a24225188254caf18a8ef
正文到此结束
Loading...