Spring源码学习(三)炒鸡丁与populateBean没区别

Easter79
• 阅读 526

逻辑说明

populateBean的流程

炒鸡丁的流程

1.执行InstantiationAwareBeanPostProcessor

的postProcessAfterInstantiation

(在设置属性前去修改Bean的状态,也可以控制是否继续填充Bean)

作为一个已婚男人炒菜之前,请示老婆,这很重要。

我:“我炒宫爆鸡丁了,有特殊要求吗?”

老婆大人:“没有要求,炒吧”。

2.注入属性到PropertyValues中(autowireByName/autowireByType)

初步准备食材

准备鸡肉,郫县豆瓣酱,花生米,黄瓜

3.执行InstantiationAwareBeanPostProcessor的postProcessPropertyValues,

对解析完但未设置的属性再进行处理

切菜 鸡肉切丁,黄瓜切小块。

4.对dependency-check属性的支持,默认是不校验

 

5.将PropertyValues中的属性值设置到BeanWrapper中

下锅,炒熟出锅

autowirebyType的大致逻辑

看了源码总结如下:

  1. 不处理简单属性,即不处理:Enum,CharSequence,Number,Date,URI,Locale等。(具体可以查看org.springframework.beans.BeanUtils#isSimpleProperty这个方法。)
  2. 不对Object类型的属性进行自动注入, 没有意义,技术无法实现
  3. 解析依赖resolveDependency并设置到pvs中
  4. registerDependentBean 注册当前依赖。

autowiredByType的源码注释

/**
     * Abstract method defining "autowire by type" (bean properties by type) behavior.
     * 抽象方法 定义 按类型注入
     * <p>This is like PicoContainer default, in which there must be exactly one bean
     * of the property type in the bean factory. This makes bean factories simple to
     * configure for small namespaces, but doesn't work as well as standard Spring
     * behavior for bigger applications.
     * 类似PicoContainer(非常轻量级的Ioc容器),beanFactory中一个属性类型必须有一个确切对应的bean
     * bean工厂很容易配置小的命名空间.
     * @param beanName the name of the bean to autowire by type  需要按类型注入的BeanName
     * @param mbd the merged bean definition to update through autowiring   合并后的BeanDefinition
     * @param bw the BeanWrapper from which we can obtain information about the bean  BeanWrapper对象
     * @param pvs the PropertyValues to register wired objects with 注册属性的属性值
     */
    protected void autowireByType(
            String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
        //获取类型转换器
        TypeConverter converter = getCustomTypeConverter();
        if (converter == null) {
            converter = bw;
        }
        //获取需要 注入的 非简单类型
        /**
         * 简单类型,详见
         * @see org.springframework.beans.BeanUtils#isSimpleProperty
         */
        Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
        String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);

        for (String propertyName : propertyNames) {
            try {
                PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
                // Don't try autowiring by type for type Object: never makes sense,
                // even if it technically is a unsatisfied, non-simple property.
                // 不对Object类型的属性进行自动注入, 没有意义,技术无法实现
                if (Object.class != pd.getPropertyType()) {
                    //获得属性写的方法
                    MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
                    // Do not allow eager init for type matching in case of a prioritized post-processor.
                    // 假如实现了prioritized post-processor ,在进行类型匹配时,是不允许,eager初始化(热加载)的
                    boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
                    DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
                    //解析依赖
                    Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
                    if (autowiredArgument != null) {
                        pvs.add(propertyName, autowiredArgument);
                    }
                    for (String autowiredBeanName : autowiredBeanNames) {
                        //注册依赖
                        registerDependentBean(autowiredBeanName, beanName);
                        if (logger.isTraceEnabled()) {
                            logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
                                    propertyName + "' to bean named '" + autowiredBeanName + "'");
                        }
                    }
                    autowiredBeanNames.clear();
                }
            }
            catch (BeansException ex) {
                throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
            }
        }
    }

下回写resolveDependency的逻辑。

一图胜千言

Spring源码学习(三)炒鸡丁与populateBean没区别

源码注释

    /**
     * Populate the bean instance in the given BeanWrapper with the property values
     * from the bean definition.
     * 填充bean的属性
     * @param beanName the name of the bean   bean的名称
     * @param mbd the bean definition for the bean 合并后的Bean的定义
     * @param bw the BeanWrapper with bean instance   beanWrapper的对象
     */
    @SuppressWarnings("deprecation")  // for postProcessPropertyValues
    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.
                // 跳过没有属性,null实例
                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.
        //给任何InstantiationWareBeanPostProcessors在设置属性之前修改bean的状态的机会。
        // 例如,这可用于支持属性注入
        boolean continueWithPropertyPopulation = true;
        //InstantiationWareBeanPostProcessors  可以控制是否继续填充bean
        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);

        PropertyDescriptor[] filteredPds = null;
        if (hasInstAwareBpps) {
            //有InstantiationAwareBeanPostProcessors 对象
            if (pvs == null) {
                pvs = mbd.getPropertyValues();
            }
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                    if (pvsToUse == null) {
                        if (filteredPds == null) {
                            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                        }
                        pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvsToUse == null) {
                            return;
                        }
                    }
                    pvs = pvsToUse;
                }
            }
        }
        if (needsDepCheck) {
            if (filteredPds == null) {
                filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }
            //检查依赖Dependency-check
            checkDependencies(beanName, mbd, filteredPds, pvs);
        }

        if (pvs != null) {
            //将属性值设置到Bean中
            applyPropertyValues(beanName, mbd, bw, pvs);
        }
    }

下一篇resolveDependency 预计10月7号前

点赞
收藏
评论区
推荐文章
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Easter79 Easter79
3年前
spring源码解析
前言上篇我们介绍了spring容器加载的方式,并重点介绍了基于xml配置解析和注解扫描两种容器加载的方式,封装和注册beandefinition的过程。今天我们分享BeanDefinition注册后的另一个重要过程bean的实例化过程的源码。容器加载流程!spring源码解析spring容器加载源码(bean实
Spring竟然可以创建“重复”名称的bean?—一次项目中存在多个bean名称重复问题的排查
众所周知,在Spring中时不能够创建两个名称相同的bean的,否则会在启动时报错:但是我却在我们的spring项目中发现了两个相同名称的bean,并且项目也可以正常启动,对应的bean也可以正常使用。
Easter79 Easter79
3年前
spring源码分析
   在spring源码中,在很多地方都会出现PropertyEditor,那么属性编辑器用来干什么的呢?属性编辑器主要应用在以下两个方面:使用PropertyEditors设置Bean属性。当你在XML文件中声明的bean的属性类型为java.lang.String时,Spring将在容器初始化该bean时使用ClassEditor将Str
Easter79 Easter79
3年前
Spring中管理Bean依赖注入之后和Bean销毁之前的行为
    对于Singleton作用域的Bean,Spring容器将会跟踪它们的生命周期,容器知道何时实例化结束、何时销毁。Spring可以管理Bean在实例化结束之后和Bean销毁之前的行为。Bean依赖关系注入之后的行为:    Spring提供了两种方式在Bean全部属性设置成功后执行特定的行为:在Spring配置文件
Stella981 Stella981
3年前
Spring 学习笔记(三):Spring Bean
1Bean配置Spring可以看做是一个管理Bean的工厂,开发者需要将Bean配置在XML或者Properties配置文件中。实际开发中常使用XML的格式,其中<bean中的属性或子元素如下:id:Bean在BeanFactory中的唯一标识,在代码中通过BeanFac
Easter79 Easter79
3年前
Spring高级进阶:BeanFactoryPostProcessor
BeanFactoryPostProcessor是实现spring容器功能扩展的重要接口,例如修改bean属性值,实现bean动态代理等。很多框架都是通过此接口实现对spring容器的扩展,例如mybatis与spring集成时,只定义了mapper接口,无实现类,但spring却可以完成自动注入,是不是很神奇?本文将通过简单的例子,展现BeanFacto
Easter79 Easter79
3年前
Spring高级应用之注入嵌套Bean
在Spring中,如果某个Bean所依赖的Bean不想被Spring容器直接访问,可以使用嵌套Bean。和普通的Bean一样,使用<bean元素来定义嵌套的Bean,嵌套Bean只对它的外部的Bean有效,Spring容器无法直接访问嵌套的Bean,因此定义嵌套Bean也无需指定id属性。如下配置片段是一个嵌套Bean的示例:<bean id
Easter79 Easter79
3年前
Spring源码学习(四)在单值注入时如何按类型查找匹配的Bean
这是我学习Spring源码之后的第四篇文章,如果你想了解,之前的3篇文章请您查阅:前3篇blog的地址:1.Spring源码学习()别怕,老外点中餐与AbstractBeanFactory.getBean的主流程差不多(https://my.oschina.net/floor/blog/3106015)2.Spring源码学习
Easter79 Easter79
3年前
Spring表达式语言:SpEL
1、Spring表达式语言(简称:SpEL):是一个支持运行时查询和操作对象图的强大的表达式语言。2、语法类似于EL:SpEL使用{...}作为定界符,所有在大括号内的字符都被认为是SpEL。3、SpEL为bean的属性进行动态赋值提供了便利。4、通过SpEL可以实现:\通过bean的id对bean进行引用\调用方法以及引用对象
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k