《Spring技术内幕》学习笔记3--自动依赖装配autowiring

Spring IoC容器提供了两种管理Bean依赖关系的方式:
显示的依赖注入:通过BeanDefinition的属性值和构造函数以显示的方式对Bean的依赖关系进行管理。
自动依赖装配autowiring:在自动装配中,不需要对Bean属性做显示的依赖关系说明,只需要配置好autowiring属性,Ioc容器会根据这个属性的配置,使用反射自动查找属性的类型或者名字,然后基于属性的类型或者名字来自动匹配Ioc容器中的Bean,从而自动的完成依赖注入。

自动依赖装配autowiring优点:能够减少用户配置Bean的工作量,完成依赖管理的自动化

autowiring的实现原理

  • AbstractAutoWireCapableBeanFactory对Bean实例进行属性依赖注入

    在前面对Spring IoC容器的依赖注入过程源码分析中,我们已经知道了容器对Bean实例对象的属性注入的处理发生在AbstractAutoWireCapableBeanFactory类中的populateBean方法中

    应用第一次通过getBean方法(配置了lazy-init预实例化属性的除外)向IoC容器索取Bean时,容器创建Bean实例对象,并且对Bean实例对象进行属性依赖注入,AbstractAutoWireCapableBeanFactory的populateBean方法就是实现Bean属性依赖注入的功能,其主要源码如下:

    protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) {  
            //获取Bean定义的属性值,并对属性值进行处理  
            PropertyValues pvs = mbd.getPropertyValues();  
            ……  
            //对依赖注入处理,首先处理autowiring自动装配的依赖注入  
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||  
                    mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {  
                MutablePropertyValues newPvs = new MutablePropertyValues(pvs);  
                //根据Bean名称进行autowiring自动装配处理  
                if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {  
                    autowireByName(beanName, mbd, bw, newPvs);  
                }  
                //根据Bean类型进行autowiring自动装配处理  
                if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {  
                    autowireByType(beanName, mbd, bw, newPvs);  
                }  
            }  
    //对非autowiring的属性进行依赖注入处理  
    ……  
        }   
  • Spring IoC容器根据Bean名称或者类型进行autowiring自动依赖注入:

对autowireByName来说,它首先需要得到当前Bean的属性名,这些属性名已经在BeanWrapper和BeanDefinition中封装好了,然后是对这一系列属性名进行匹配的过程。在匹配的过程中,因为已经有了属性的名字,所以可以直接使用属性名作为Bean名字向容器索取Bean,这个getBean会触发当前Bean的依赖Bean的依赖注入,从而得到属性对应的依赖Bean。在执行完这个getBean后,把这个依赖Bean注入到当前Bean的属性中去,这样就完成了通过这个依赖属性名自动完成依赖注入的过程。

//根据名称对属性进行自动依赖注入  
protected void autowireByName(  
            String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {  
    //对Bean对象中非简单属性(不是简单继承的对象,如8中原始类型,字符串,URL等//都是简单属性)进行处理  
        String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);  
        for (String propertyName : propertyNames) {  
            //如果Spring IoC容器中包含指定名称的Bean  
            if (containsBean(propertyName)) {  
        //调用getBean方法向IoC容器索取指定名称的Bean实例,迭代触发属性的//初始化和依赖注入  
                Object bean = getBean(propertyName);  
                //为指定名称的属性赋予属性值  
                pvs.add(propertyName, bean);  
                //指定名称属性注册依赖Bean名称,进行属性依赖注入  
                registerDependentBean(propertyName, beanName);  
                if (logger.isDebugEnabled()) {  
                    logger.debug("Added autowiring by name from bean name '" + beanName +  
                            "' via property '" + propertyName + "' to bean named '" + propertyName + "'");  
                }  
            }  
            else {  
                if (logger.isTraceEnabled()) {  
                    logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +  
                            "' by name: no matching bean found");  
                }  
            }  
        }  
    }  
//根据类型对属性进行自动依赖注入  
protected void autowireByType(  
            String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {  
        //获取用户定义的类型转换器  
        TypeConverter converter = getCustomTypeConverter();  
        if (converter == null) {  
            converter = bw;  
        }  
        //存放解析的要注入的属性  
        Set<String> autowiredBeanNames = new LinkedHashSet<String>(4);  
//对Bean对象中非简单属性(不是简单继承的对象,如8中原始类型,字符  
//URL等都是简单属性)进行处理  
        String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);  
        for (String propertyName : propertyNames) {  
            try {  
                //获取指定属性名称的属性描述器  
                PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);  
                //不对Object类型的属性进行autowiring自动依赖注入  
                if (!Object.class.equals(pd.getPropertyType())) {  
                    //获取属性的setter方法  
                    MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);  
                    //检查指定类型是否可以被转换为目标对象的类型  
                    boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass());  
                    //创建一个要被注入的依赖描述  
                    DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);  
                    //根据容器的Bean定义解析依赖关系,返回所有要被注入的Bean对象  
                    Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);  
                    if (autowiredArgument != null) {  
                        //为属性赋值所引用的对象  
                        pvs.add(propertyName, autowiredArgument);  
                    }  
                    for (String autowiredBeanName : autowiredBeanNames) {  
//指定名称属性注册依赖Bean名称,进行属性依赖注入  
                        registerDependentBean(autowiredBeanName, beanName);  
                        if (logger.isDebugEnabled()) {  
                            logger.debug("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);  
            }  
        }  
    }  

通过上面的源码分析,我们可以看出来通过属性名进行自动依赖注入的相对比通过属性类型进行自动依赖注入要稍微简单一些,但是真正实现属性注入的是DefaultSingletonBeanRegistry类的registerDependentBean方法。

  • DefaultSingletonBeanRegistry的registerDependentBean方法对属性注入:
    //为指定的Bean注入依赖的Bean  
    public void registerDependentBean(String beanName, String dependentBeanName) {  
            //处理Bean名称,将别名转换为规范的Bean名称  
            String canonicalName = canonicalName(beanName);  
            //多线程同步,保证容器内数据的一致性  
    //先从容器中:bean名称-->全部依赖Bean名称集合找查找给定名称Bean的依赖Bean  
            synchronized (this.dependentBeanMap) {  
                //获取给定名称Bean的所有依赖Bean名称  
                Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);  
                if (dependentBeans == null) {  
                    //为Bean设置依赖Bean信息  
                    dependentBeans = new LinkedHashSet<String>(8);  
                    this.dependentBeanMap.put(canonicalName, dependentBeans);  
                }  
                //向容器中:bean名称-->全部依赖Bean名称集合添加Bean的依赖信息  
                //即,将Bean所依赖的Bean添加到容器的集合中  
                dependentBeans.add(dependentBeanName);  
            }  
    //从容器中:bean名称-->指定名称Bean的依赖Bean集合找查找给定名称  
    //Bean的依赖Bean  
            synchronized (this.dependenciesForBeanMap) {  
                Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);  
                if (dependenciesForBean == null) {  
                    dependenciesForBean = new LinkedHashSet<String>(8);  
                    this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);  
                }  
                //向容器中:bean名称-->指定Bean的依赖Bean名称集合添加Bean的依赖信息  
    //即,将Bean所依赖的Bean添加到容器的集合中  
                dependenciesForBean.add(canonicalName);  
            }  
        }  

通过对autowiring的源码分析,我们可以看出,autowiring的实现过程:
对Bean的属性迭代调用getBean方法,完成依赖Bean的初始化和依赖注入。
将依赖Bean的属性引用设置到被依赖的Bean属性上。
将依赖Bean的名称和被依赖Bean的名称存储在IoC容器的集合中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值