• Spring9 : Autowire(自动装配)机制


    原文出处: 五月的仓颉

    为什么Spring要支持Autowire(自动装配)

    先写几个类,首先定义一个Animal接口表示动物:

    1
    2
    3
    4
    5
    public interface Animal {
      
         public void eat();
          
    }

    写一个Animal接口的实现Tiger类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Tiger implements Animal {
     
        @Override
        public void eat() {
            System.out.println("Tiger.eat()");
        }
         
        @Override
        public String toString() {
            return "I'm a tiger";
        }
    }

    写一个动物园类Zoo,持有Animal接口,表示动物园中有动物:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class Zoo {
         
        private Animal animal;
         
        public Animal getAnimal() {
            return animal;
        }
     
        public void setAnimal(Animal animal) {
            this.animal = animal;
        }
     
        @Override
        public String toString() {
            if (animal == null) {
                return null;
            }
            return animal.toString();
        }
         
    }

    配置一下spring文件,由于这个功能研究的是Autowire,因此我命名为autowire.xml:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
     
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
     
        <bean id="tiger" class="org.xrq.action.by.Tiger" />
         
        <bean id="zoo" class="org.xrq.action.by.Zoo">
            <property name="animal" ref="tiger" />
        </bean>
             
    </beans>

    Spring引入Autowire(自动装配)机制就是为了解决<bean>标签下<property>标签过多的问题,<property>标签过多会引发两个问题:

    • 如果一个Bean中要注入的对象过多,比如十几二十个(这是很正常的),那将导致Spring配置文件非常冗长,可读性与维护性差
    • 如果一个Bean中要注入的对象过多,配置麻烦且一不小心就容易出错

    因此,为了解决使用<property>标签注入对象过多的问题,Spring引入自动装配机制,简化开发者配置难度,降低xml文件配置大小。

    使用Autowire去除<property>标签

    下面来看一下使用Autowire去除<property>,autowire有两处点:

    • 可以配置在<beans>根标签下,表示对全局<bean>起作用,属性名为default-autowire
    • 可以配置在<bean>标签下,表示对当前<bean>起作用,属性名为autowire

    通常都是在<beans>根标签下配置自动装配比较多,default-autowire有四种取值:

    • no:默认,即不进行自动装配,每一个对象的注入比如依赖一个<property>标签
    • byName:按照beanName进行自动装配,使用setter注入
    • byType:按照bean类型进行自动装配,使用setter注入
    • constructor:与byType差不多,不过最终属性通过构造函数进行注入

    这里研究的是去除<property>标签,因此第一种不管;constructor装配不太常用,因此这里也不管,重点看最常用的byName与byType,至于具体使用哪种根据自己的业务特点进行相应的设置。

    首先看一下byName,byName意为在spring配置文件中查询beanName与属性名一致的bean并进行装配,若类型不匹配则报错,autowire.xml如果使用byName进行属性装配,那么将改成以下的形式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
     
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
     
        default-autowire="byName">
         
        <bean id="animal" class="org.xrq.action.by.Tiger" />
         
        <bean id="zoo" class="org.xrq.action.by.Zoo" />
             
    </beans>

    看到Zoo中有一个名为animal的属性,我将Tiger这个bean也命名为animal,由于Tiger是Animal接口的实现类,因此Spring可以找到beanName为animal的bean并自动装配到Zoo的animal属性中,这就是byName的自动装配形式。

    接着看一下byType的自动装配形式,byType意为在spring配置文件中查询与属性类型一致的bean并进行装配,若有多个相同类型则报错(下一部分讲),autowire.xml如果使用byType进行属性装配,那么将改成以下的形式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
     
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
     
        default-autowire="byType">
         
        <bean id="tiger" class="org.xrq.action.by.Tiger" />
         
        <bean id="zoo" class="org.xrq.action.by.Zoo" />
             
    </beans>

    将Tiger命名为tiger(将bean命名为类名首字母小写也比较符合规范),由于Tiger是Animal接口的实现类,因此Spring找到了Tiger并自动装配到Zoo的animal属性中,这就是byType的自动装配形式。

    byType装配出现多个相同类型的bean及解决方案

    前面演示了,byType的装配方式是在Spring配置文件中寻找属性类型与bean类型一致的bean,那么有一个问题,就是如果属性类型在Spring配置文件中有多个相同类型的bean会出现什么样的情况?为了探究一下这个问题,先定义另外一个Animal接口的实现类,叫做lion:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Lion implements Animal {
     
        @Override
        public void eat() {
            System.out.println("Lion.eat()");
        }
     
        @Override
        public String toString() {
            return "I'm a lion";
        }
    }

    接着,在Spring配置文件中定义一下Lion这个类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
     
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
     
        default-autowire="byType">
         
        <bean id="tiger" class="org.xrq.action.by.Tiger" />
        <bean id="lion" class="org.xrq.action.by.Lion" />
         
        <bean id="zoo" class="org.xrq.action.by.Zoo" />
             
    </beans>

    运行一个测试类,结果为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'zoo' defined in class path resource [spring/autowire.xml]:
    Unsatisfied dependency expressed through bean property 'animal': : No unique bean of type [org.xrq.action.by.Animal] is defined: expected single matching bean but
    found 2: [tiger, lion]; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.xrq.action.by.Animal] is
    defined: expected single matching bean but found 2: [tiger, lion]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1166)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1058)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:516)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:455)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)

    意思很明显:想要通过byType方式为animal进行装配却找到了两个符合要求的bean,分别为tiger与lion,这导致了没有唯一的bean可以对animal进行装配。

    这个问题有两种解决方案,假如现在我要装配的是lion这个bean,第一种解决方案是将不需要进行自动装配的bean进行排除,对不需要进行自动装配的bean设置属性autowire-candidate=”false”即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
     
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
     
        default-autowire="byType">
         
        <bean id="tiger" class="org.xrq.action.by.Tiger" autowire-candidate="false" />
        <bean id="lion" class="org.xrq.action.by.Lion" />
         
        <bean id="zoo" class="org.xrq.action.by.Zoo" />
             
    </beans>

    candidate顾名思义,即候选人的意思,autowire-candidate=”false”即这个bean我不想让它作为自动装配的候选者,既然tiger不是自动装配的候选者,那么animal类型在Spring容器中能自动装配的也就只有一个lion了,Spring自动装配lion,不会有问题。

    第一种思路是排除那些不需要作为自动装配候选者的bean,第二种思路就从相反逻辑出发,设置当发现有多个候选者的时候优先使用其中的哪个候选者,对要作为自动装配候选者的bean设置primary=”true”即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
     
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
     
        default-autowire="byType">
         
        <bean id="tiger" class="org.xrq.action.by.Tiger" />
        <bean id="lion" class="org.xrq.action.by.Lion" primary="true" />
         
        <bean id="zoo" class="org.xrq.action.by.Zoo" />
             
    </beans>

    这种方式同样也可以将lion装配到animal属性中而不会报错。

    from: http://www.importnew.com/24731.html

  • 相关阅读:
    55、分页查询employees表,每5行一页,返回第2页的数据
    54、查找排除当前最大、最小salary之后的员工的平均工资avg_salary
    53、按照分组拼接字段
    52、获取Employees中的first_name
    51、查找字符串'10,A,B' 中逗号','出现的次数cnt
    图片素材
    软件下载
    一款高效卸载软件
    《单独.17 人的困境》(摘抄)
    Markdown的简单使用
  • 原文地址:https://www.cnblogs.com/GarfieldEr007/p/7078365.html
Copyright © 2020-2023  润新知