美文网首页
spring-BeanFactory学习(二)

spring-BeanFactory学习(二)

作者: 非典型_程序员 | 来源:发表于2019-04-14 21:48 被阅读0次

上周进入了新的项目组,主要是对原有微服务进行优化,然后就遇到了如何将日志分类处理的问题,即将服务之间调用和第三方调用分开,并分别存储。但是因为目前项目组的人员都不是原有的开发人员,很多配置都还不知道如何处理,有点头大。等这部分优化完以后专门记录一下吧。今天还是继续学习BeanFactory的源码,上次主要看了BeanFactory的常用成员变量以及创建bean和初始化bean的方法,今天主要学习下怎么配置bean以及装配bean。

一、自动装配bean

通过应用after-instantiation回调和bean属性后置处理来填充给定的bean实例,我们先看代码:

@Override
public void autowireBean(Object existingBean) {
    // Use non-singleton bean definition, to avoid registering bean as dependent bean.
    RootBeanDefinition bd = new RootBeanDefinition(ClassUtils.getUserClass(existingBean));
    bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
    bd.allowCaching = ClassUtils.isCacheSafe(bd.getBeanClass(), getBeanClassLoader());
    BeanWrapper bw = new BeanWrapperImpl(existingBean);
    initBeanWrapper(bw);
    populateBean(bd.getBeanClass().getName(), bd, bw);
}

首先还是再说下RootBeanDefinition,这个很重要一个概念而且用的地方也很多。RootBeanDefinition表示合并的bean定义,它在运行时支持BeanFactory中的特定bean,它可能是从多个原始bean定义创建的,这些定义相互继承,通常注册为GenericBeanDefinitions。RootBeanDefinition本质上是运行时的“统一”bean定义视图。RootBeanDefinition也可用于在配置阶段注册单个bean定义,但是从spring2.5以后一般选择以编程方式注册bean定义的首选方法是GenericBeanDefinition。GenericBeanDefinition的优点是它允许动态定义父依赖关系,而不是将角色“硬编码”为根bean定义。
上面的代码先根据bean创建RootBeanDefinition对象,并设置其作用域为"prototype",从而避免其成为依赖bean。然后根据给定的bean创建BeanWrapper对象,即bean的包装对象。接着对BeanWrapper对象进行初始化,最后是执行populateBean方法,即使用属性值填充给定BeanWrapper中的bean实例(就是传入的bean对象),下面看看populateBean的代码:

    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        if (bw == null) {
            if (mbd.hasPropertyValues()) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
            }
            else {
                // Skip property population phase for null instance.
                return;
            }
        }

        // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
        // state of the bean before properties are set. This can be used, for example,
        // to support styles of field injection.
        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;
        }

        PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

        if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
            // Add property values based on autowire by name if applicable.
            if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
                autowireByName(beanName, mbd, bw, newPvs);
            }
            // Add property values based on autowire by type if applicable.
            if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
                autowireByType(beanName, mbd, bw, newPvs);
            }
            pvs = newPvs;
        }

        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
        boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

        if (hasInstAwareBpps || needsDepCheck) {
            if (pvs == null) {
                pvs = mbd.getPropertyValues();
            }
            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);
            }
        }

        if (pvs != null) {
            applyPropertyValues(beanName, mbd, bw, pvs);
        }
    }

方法比较长,简单的看一下,这个方法的主要内容就是使用RootBeanDefinition中的属性值填充给定BeanWrapper中的bean实例。
1、首先判断BeanWrapper是否为null,是则判断RootBeanDefinition对象是否有属性值,如果有直接抛出异常,否则直接return。
2、如果RootBeanDefinition对象不是合成的,合成的意思这个bean不是由应用本身定义的。且BeanFactory的hasInstantiationAwareBeanPostProcessors属性值为true,即有InstantiationAwareBeanPostProcessors。对BeanFactory的beanPostProcessors集合进行遍历,如果遇到BeanPostProcessor是InstantiationAwareBeanPostProcessor的实例,那么会调用该实例的postProcessAfterInstantiation方法,如果该方法返回值为false,则将变量continueWithPropertyPopulation的值设为false,并接受循环,不过这个方法的结果好像永远返回true.....
3、将RootBeanDefinition对象的属性值赋给变量pvs。如果RootBeanDefinition对象的装配方式为按类型装配或者按名称装配,则根据pvs创建MutablePropertyValues对象,然后的装配类型分别调用相应的方法进行相关属性值的添加,最后将MutablePropertyValues对象赋值给pvs。
4、如果BeanFactory的hasInstantiationAwareBeanPostProcessors属性值为true或者RootBeanDefinition的dependencyCheck属性值不等于AbstractBeanDefinition.DEPENDENCY_CHECK_NONE。调用filterPropertyDescriptorsForDependencyCheck方法,从给定的BeanWrapper对象中提取过滤出一组PropertyDescriptors,不包括那些在忽略的依赖项接口上定义的已忽略的依赖项类型或属性。如果BeanFactory的hasInstantiationAwareBeanPostProcessors属性值为true,对BeanFactory的beanPostProcessors集合进行遍历,如果遇到BeanPostProcessor是InstantiationAwareBeanPostProcessor的实例,则调用该实例的postProcessPropertyValues方法,即在工厂将它们应用于给定bean之前对给定属性值进行后处理,如果该方法返回结果为null,直接return;如果RootBeanDefinition的dependencyCheck属性值不等于AbstractBeanDefinition.DEPENDENCY_CHECK_NONE,调用checkDependencies方法,该方法执行依赖性检查,以确定相关属性已经设置成对外可见。
5、如果变量pvs不为null,执行applyPropertyValues方法,这个方法应用给定的属性值,解析对此Bean工厂中其他bean的任何运行时引用。必须使用深拷贝,以便不会永久修改这些属性。
如果只看autowireBean方法,好像没那么多内容,但是往下看得话其实还是很多的,当然这些内容只是我静态的根据代码分析,并没有启动项目进行debug。

二、配置bean

下面看下configureBean方法的代码:

    public Object configureBean(Object existingBean, String beanName) throws BeansException {
        markBeanAsCreated(beanName);
        BeanDefinition mbd = getMergedBeanDefinition(beanName);
        RootBeanDefinition bd = null;
        if (mbd instanceof RootBeanDefinition) {
            RootBeanDefinition rbd = (RootBeanDefinition) mbd;
            bd = (rbd.isPrototype() ? rbd : rbd.cloneBeanDefinition());
        }
        if (bd == null) {
            bd = new RootBeanDefinition(mbd);
        }
        if (!bd.isPrototype()) {
            bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
            bd.allowCaching = ClassUtils.isCacheSafe(ClassUtils.getUserClass(existingBean), getBeanClassLoader());
        }
        BeanWrapper bw = new BeanWrapperImpl(existingBean);
        initBeanWrapper(bw);
        populateBean(beanName, bd, bw);
        return initializeBean(beanName, existingBean, bd);
    }

这个方法主要为配置给定的原始bean,自动装配bean属性,应用bean属性值,应用工厂回调(如setBeanName和setBeanFactory),还应用所有bean后置处理器(包括可能包装给定原始bean的那些)。
1、首先将给定bean名称标记为已创建或者即将创建,这个方法会判断BeanFactory的alreadyCreated集合中是否有当前bean名称,没有则添加,且会从mergedBeanDefinitions清除该bean的名称。
2、根据给定bean名称,调用getMergedBeanDefinition方法获取一个"merged"的BeanDefinition,变量名称为mbd,实际上是一个RootBeanDefinition实例。如果mbd是一个RootBeanDefinition实例,将mbd赋值给变量rbd,如果rdb的作用域是"prototype",则将rdb赋值给变量bd,否则以rdb为源重新创建一个RootBeanDefinition对象,并赋值给bd。
3、如果变量bd为null,则以mbd为源创建新的RootBeanDefinition对象,并赋值给bd;如果bd的作用域不是"prototype",则将其作用域设置为"prototype",并设置其allowCaching的值,根据给定bean的class对象以及ClassLoader判断。
4、创建BeanWrapper对象并初始化,然后执行populateBean方法,使用属性值填充给定BeanWrapper中的bean实例,这一步和autowireBean中是一样的。
5、调用initializeBean方法,并返回结果,initializeBean上一次的学习中已经讲过了,这里不再赘述了。

三、自动装配

看到这个方法的时候感觉有点奇怪,autowire和autowireBean感觉名称差不多啊。autowireBean方法是通过应用after-instantiation回调和bean属性后置处理来填充给定的bean实例,可见实在bean实例化之后执行。而autowire方法通过使用指定的autowire策略实例化给定类的新bean实例,也就是说autowire其实是实例化bean的,而autowireBean填充bean的属性,二者有先后关系,另外autowireBean方法为void,而autowire返回bean实例。我们看下autowire的代码:

public Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
        // Use non-singleton bean definition, to avoid registering bean as dependent bean.
        final RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);
        bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
        if (bd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR) {
            return autowireConstructor(beanClass.getName(), bd, null, null).getWrappedInstance();
        }
        else {
            Object bean;
            final BeanFactory parent = this;
            if (System.getSecurityManager() != null) {
                bean = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                        getInstantiationStrategy().instantiate(bd, null, parent),
                        getAccessControlContext());
            }
            else {
                bean = getInstantiationStrategy().instantiate(bd, null, parent);
            }
            populateBean(beanClass.getName(), bd, new BeanWrapperImpl(bean));
            return bean;
        }
    }

1、首先根据给定的bean class对象、装配模式和是否需要依赖检查作为参数创建RootBeanDefinition对象,并将其作用域设置为"prototype"。
2、如果RootBeanDefinition的getResolvedAutowireMode值等于AUTOWIRE_CONSTRUCTOR,即使用的是构造函数装配,执行autowireConstructor方法获取BeanWrapper实例,然后调用该实例的getWrappedInstance方法,返回该实例包装的bean对象。这里面autowireConstructor方法稍微有些复杂。
3、如果RootBeanDefinition的getResolvedAutowireMode不等于AUTOWIRE_CONSTRUCTOR,判断系统的SecurityManager是否为null,为null,执行第4步;不为null,则调用 AccessController的doPrivileged方法,代码里用到了lambda表达式,有点看不大懂....表示lambda写着是爽,但是维护的话比较麻烦。doPrivileged方法,主要有两个参数,一个是PrivilegedAction,一个是AccessControlContext。PrivilegedAction是通过getInstantiationStrategy()方法得到创建bean实例的InstantiationStrategy实例,然后执行其instantiate方法创建bean对象,而getAccessControlContext方法获取AccessControlContext实例。
4、这步和第3步lambda表达式那里基本相同,不再说了,这里直接获取对象实例。
5、执行populateBean方法,然后返回bean。


今天这几个方法也都是定义在AbstractAutowireCapableBeanFactory类里面的,此外还有destroyBean等方法,下次继续学习吧,只是感觉自己好像并没有理解其中的原理,只能跟着代码学习,不知道是不是自己的方法有问题。

相关文章

  • spring-BeanFactory学习(二)

    上周进入了新的项目组,主要是对原有微服务进行优化,然后就遇到了如何将日志分类处理的问题,即将服务之间调用和第三方调...

  • spring-BeanFactory学习(一)

    上周主要了解了spring boot项目启动过程中,beanFactory的继承体系,以及beanFactory是...

  • Spring-BeanFactory和FactoryBean的区

    1.BeanFactory和FactoryBean的区别 BeanFactory是一个接口,提供了IOC容器最基本...

  • 学习二

    兴趣和任务 我写的,所分享的东西都是我看到,听到,以及胡思乱想想到的东西;我只是把触动我的内容转述出来。我所说的一...

  • 学习(二)

    任何一个企业要想在剧烈变动的市场中生存和发展,必须有能力及时察觉组织内外环境的变化,并积极做出调整,学习新的技能,...

  • 学习二

    之前讲到我来北京是为了学习,但是我在这期间不是无时无刻都在学习,在教室的闲散之余,我总爱玩起我的飞车游戏。但是我真...

  • 学习(二)

    今天我和同事S姐上的早班,今天我们主要学习了打价签。 刚开始我们两人先熟悉打价签的流程,接着我们慢慢练习起来。 等...

  • 二,学习。

    2007年。学习。 紧张的中招考试结束。上了梦想的高中,人一下子就慵懒了起来,仿佛一只脚已经踏进了大学校园,只要稍...

  • 学习(二)

    上海依旧阴雨绵绵,时大时小。 今天看完了艾森豪威尔法则,现在来回忆一下学习的内容加深理解,首先,把一则小故事回忆一...

  • 学习 二

    涂口红 一:选择口红原则 1、根据年龄来选购口红: 年轻而皮肤较白的宝宝,口红色彩可略鲜明些,如淡红、变色口红及桃...

网友评论

      本文标题:spring-BeanFactory学习(二)

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