GetBean源码全面解读

栏目: Java · 发布时间: 7年前

内容简介:在上篇文章刨坑的过程中,顺便研究了一波spring源码,初始看的也是头晕,后面逐渐捋好了思路。个人感觉spring还是个大工程的,这篇文章解读的肯定也有自己理解不到位的部分,希望各位看官能多讨论讨论。最后会附上一副getBean方法的流程图,希望能打开大家看这部分源码的思路。(本文基于spring 5.1.2版本)整个操作大概是以下几步:这里这么设计是为了解决循环依赖的问题。若A依赖B,B依赖C,C又依赖A,这样三个bean就形成了一个环(这里只是针对set方法注入的bean,构造器注入还是会有循环依赖的

前言

在上篇文章刨坑的过程中,顺便研究了一波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


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Practical JavaScript, DOM Scripting and Ajax Projects

Practical JavaScript, DOM Scripting and Ajax Projects

Frank Zammetti / Apress / April 16, 2007 / $44.99

http://www.amazon.com/exec/obidos/tg/detail/-/1590598164/ Book Description Practical JavaScript, DOM, and Ajax Projects is ideal for web developers already experienced in JavaScript who want to ......一起来看看 《Practical JavaScript, DOM Scripting and Ajax Projects》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换