为什么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()");
6 }
7
8 @Override
9 public String toString() {
10 return "I'm a tiger";
11 }
12 }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

参看链接:

https://www.cnblogs.com/PengChengLi/p/10516939.html

https://www.cnblogs.com/xrq730/p/6706128.html

 

Spring自动装配(二)的更多相关文章

  1. spring 自动装配 default-autowire=&quot;byName/byType&quot;

    <PRE class=html name="code">spring 自动装配 default-autowire="byName/byType"   ...

  2. Spring 自动装配 Bean

    Spring3系列8- Spring 自动装配 Bean 1.      Auto-Wiring ‘no’ 2.      Auto-Wiring ‘byName’ 3.      Auto-Wiri ...

  3. Spring自动装配Bean详解

    1.      Auto-Wiring ‘no’ 2.      Auto-Wiring ‘byName’ 3.      Auto-Wiring ‘byType 4.      Auto-Wirin ...

  4. Spring自动装配----注解装配----Spring自带的@Autowired注解

    Spring自动装配----注解装配----Spring自带的@Autowired注解 父类 package cn.ychx; public interface Person { public voi ...

  5. Spring系列七:Spring 自动装配

    相思相见知何日?此时此夜难为情. 概述 在Spring框架中,在配置文件中声明bean的依赖关系是一个很好的做法,因为Spring容器能够自动装配协作bean之间的关系.这称为spring自动装配. ...

  6. Spring自动装配歧义性笔记

    Spring自动装配歧义性笔记 如果系统中存在两个都实现了同一接口的类,Spring在进行@Autowired自动装配的时候,会选择哪一个?如下: // 一下两个类均被标记为bean @Compone ...

  7. Spring 自动装配及其注解

    一.属性自动装配 首先,准备三个类,分别是User,Cat,Dog.其中User属性拥有Cat和Dog对象. package com.hdu.autowire; public class User { ...

  8. 峰Spring4学习(4)spring自动装配

    一.自动装配: Model类: People.java: package com.cy.entity; public class People { private int id; private St ...

  9. Spring——自动装配(@Autowired/@Profile/底层组件)

    本文介绍Spring中关于自动装配的方法和规则,以及@Profile动态激活的用法和一个例子. 一.@Autowired自动装配 @Autowired注解可以加在构造器.属性.方法.方法参数上. 自动 ...

随机推荐

  1. 【NX二次开发】Block UI 整形

    属性说明 常规         类型 描述     BlockID     String 控件ID     Enable     Logical 是否可操作     Group     Logical ...

  2. Redis五种基础与三种高级数据结构解析

    记得点赞+关注呦. 前言 在 Redis 最重要最基础就属 它丰富的数据结构了,Redis 之所以能脱颖而出很大原因是他数据结构丰富,可以支持多种场景.并且 Redis 的数据结构实现以及应用场景在面 ...

  3. es6快速入门 系列 - async

    其他章节请看: es6 快速入门 系列 async 前文我们已经知道 promise 是一种异步编程的选择.而 async 是一种用于执行异步任务更简单的语法. Tip:建议学完 Promise 在看 ...

  4. Java操作SQL数据库(JDBC)

    0.引入驱动jar包 使用jdbc进行具体操作前,需要引入相关数据库的jar包, 或者使用mave管理依赖 <!-- https://mvnrepository.com/artifact/mys ...

  5. 日常BUG-01 之 @Sl4j

    问题描述: 需要打印日志,使用的是lombok包中的sl4j,lombok依赖如下: <dependency> <groupId>org.projectlombok</g ...

  6. 使用 python 把一个文件生成 C 语言中的数组并保存到头文件中

    (一)要做什么 之前有这么一个需求,是要把一个二进制文件里面的数据,转换成 C 代码里面的数组,可以看之前的一篇文章: NUC980 运行 RT-Thread 驱动 SPI 接口 OLED 播放 ba ...

  7. 【问答分享第一弹】MySQL锁总结:MySQL行锁、表锁、排他锁、共享锁的特点

    大家好,我是小于哥哈.前几天能分享了第一期面试题,MySQL 中有哪几种锁 和 这些锁各有哪些特点 ,这道面试题是经常会被问到的一个面试题,大家反馈的都挺不错的.今天特此来总结一下. 首发于公众号[终 ...

  8. webpack(6)webpack处理图片

    图片处理url-loader(webpack5之前的处理方式) 在项目开发中,我们时长会需要使用到图片,比如在img文件夹中有图片test1.png,然后在normal.css中会引用到图片 body ...

  9. Mybatis学习(5)与spring3集成

    在这一系列文章中,前面讲到纯粹用mybatis 连接数据库,然后 进行增删改查,以及多表联合查询的的例子,但实际项目中,通常会用 spring 这个沾合剂来管理 datasource 等.充分利用sp ...

  10. 使用xcode实现IM的那些坑

    想用xcode基于XMPP实现即时通讯,mac必须安装openfire(xmpp服务器),mysql(本地数据库,用于配置openfire),JDK(打开openfire必须本地具备java环境),x ...