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

时间: 2024-10-26 14:27:22

Spring9 : Autowire(自动装配)机制的相关文章

隐式的bean发现与自动装配机制

使用beans.xml文件进行bean的创建和注入通常是可行的,但在便利性上Spring提供了更简单的方法--自动装配 接下来我们假设一个场景:我有若干播放器(MediaPlayer{CD播放器/MP3}),我也有很多媒体文件例如(CompactDisc{CD光盘/MP3文件}). 现在,我们需要创建两个接口MediaPlayer/CompactDisc,然后创建他们的实现CDPlayer/CompactDisc_zhoujielun.注意:CompactDisc_zhoujielun是周杰伦的

Spring Autowire自动装配

在Spring中,支持 5 自动装配模式. no – 缺省情况下,自动配置是通过"ref"属性手动设定 byName – 根据属性名称自动装配.如果一个bean的名称和其他bean属性的名称是一样的,将会自装配它. byType – 按数据类型自动装配.如果一个bean的数据类型是用其它bean属性的数据类型,兼容并自动装配它. constructor – 在构造函数参数的byType方式. autodetect – 如果找到默认的构造函数,使用"自动装配用构造";

【Spring9】AutoWire(自动装配)机制

为什么Spring要支持Autowire(自动装配) 先写几个类,首先定义一个Animal接口表示动物: 1 public interface Animal { 2 3 public void eat(); 4 5 } 写一个Animal接口的实现Tiger类: 1 public class Tiger implements Animal { 2 3 @Override 4 public void eat() { 5 System.out.println("Tiger.eat()");

Autowire(自动装配)机制

为什么Spring要支持Autowire(自动装配) 先写几个类,首先定义一个Animal接口表示动物: 1 public interface Animal { 2 3 public void eat(); 4 5 } 写一个Animal接口的实现Tiger类: 1 public class Tiger implements Animal { 2 3 @Override 4 public void eat() { 5 System.out.println("Tiger.eat()");

Spring笔记04(DI(给属性赋值),自动装配(autowire))

1.DI(给属性赋值)的四种方式: 01.Student实体类: package cn.pb.bean; /** * 学生实体类 */ public class Student { private String name; //姓名 private Integer age; //年龄 private Grade grade; //年级 @Override public String toString() { return "Student [name=" + name + "

Spring4 自动装配;方法注入

通过配置defalut-zutowire属性,Spring IOC容器可以自动为程序注入Bean;默认是no(不启用自动装配). default-autowire的类型有: byName:通过名称自动进行匹配 byType:通过属性自动进行匹配 示例如下: 一个实体类people beans.xml配置: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.spr

Spring 自动装配;方法注入

通过配置defalut-autowire属性,Spring IOC容器可以自动为程序注入Bean:默认是no(不启用自动装配). default-autowire的类型有: byName:通过名称自动进行匹配 byType:通过属性自动进行匹配 示例如下: 一个实体类people public class People{ private int id; private String name; private int age; private Dog dog; } beans.xml配置: <?

Spring4学习笔记 - 配置Bean - 自动装配 关系 作用域 引用外部属性文件

1 Autowire自动装配 1.1 使用:只需在<bean>中使用autowire元素 <bean id="student" class="com.kejian.spring.bean.autowire.Student" p:name="Tony" autowire="byName"></bean> 1.2 类型 byName 目标bean的id与属性名一置,若不匹配置为null byTy

spring boot 自动装配的实现原理和骚操作,不同版本实现细节调整,debug 到裂开......

开篇说明: 注解本身并没有什么实际的功能(非要说标记也是一个“实际”的功能的话,也可以算吧),隐藏在背后的注解处理器才是实现注解机制的核心.本篇将从这两个层面出发探索 spring boot 自动装配的秘密,并使用 spring boot 的自动装配机制来实现自动装配. 本次代码已经放到 github:https://github.com/christmad/code-share/tree/master/spring-boot-config-practice 代码中主要是做了 @Configur