Spring提供了四种类型的自动装配策略:

  • byName – 把与Bean的属性具有相同名字(或者ID)的其他Bean自动装配到Bean的对应属性中。
  • byType – 把与Bean的属性具有相同类型的其他Bean自动装配到Bean的对应属性中。
  • constructor – 把与Bean的构造器入参具有相同类型的其他Bean自动装配到Bean的对应属性中。
  • autodetect – 首先使用costructor进行自动装配。如果失败,再尝试使用byType进行自动装配。

我这里以关羽和青龙偃月刀为例: 首先定义一个武器接口Weapon:

package com.moonlit.myspring;

public interface Weapon {
public void attack();
}

然后定义一个Weapon接口的实现Falchion类:

package com.moonlit.myspring;

public class Falchion implements Weapon {
public void attack() {
System.out.println("falcon is attacking!");
}
}

定义一个英雄接口Hero:

package com.moonlit.myspring;

public interface Hero {
public void perform();
}

然后定义一个Hero接口的实现Guanyu类(代表关羽):

package com.moonlit.myspring;

public class GuanYu implements Hero {
private Weapon weapon;
public void perform() {
System.out.println("GuanYu pick up his weapon.");
weapon.attack();
}
public Weapon getWeapon() {
return weapon;
}
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
}

在不涉及自动装配的情况下,我们想要通过Spring的DI将Fachion类对象注入到Guanyu类的weapon属性中,可以新建一个xml文件(我这里取名为spring-idol.xml)并在里面填写:

spring-idol.xml:

<?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="falchion" class="com.moonlit.myspring.Falchion" />
<bean id="guanyu" class="com.moonlit.myspring.GuanYu">
<property name="weapon" ref="falchion" />
</bean> </beans>

其中最主要的内容就是两个bean的声明部分:

  <bean id="falchion" class="com.moonlit.myspring.Falchion" />
<bean id="guanyu" class="com.moonlit.myspring.GuanYu">
<property name="weapon" ref="falchion" />
</bean>

第一个bean标签定义了一个Falchion类型的bean,第二个bean标签中将第一个bean作为weapon的值装配到了weapon属性中。 然后我们可以写一个测试程序来查看效果:

package com.moonlit.practice;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.moonlit.myspring.Hero; public class AutowirePractice {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-idol.xml");
Hero guanyu = (Hero) context.getBean("guanyu");
guanyu.perform();
}
}

输出结果如下:

GuanYu pick up his weapon.
falcon is attacking!

到目前为止还没有涉及到自动装配的内容,接下来开始讲述自动装配的内容。

byName自动装配

改变spring-idol.xml中bean声明内容的形式如下:

  <bean id="weapon" class="com.moonlit.myspring.Falchion" />
<bean id="guanyu" class="com.moonlit.myspring.GuanYu" autowire="byName" />

得到一样的结果。

我们将Falchion类的id去了一个和Guanyu类的属性weapon一样的名字,并且在guanyu bean中添加了autowire="byName"用于指明装配类型是byName自动装配。这个时候guanyu bean就是在上下文中找名为weapon的bean装配到他自己的weapon属性中。

byType自动装配

改变spring-idol.xml中bean声明内容的形式如下:

  <bean id="falchion" class="com.moonlit.myspring.Falchion" />
<bean id="guanyu" class="com.moonlit.myspring.GuanYu" autowire="byType" />

得到一样的结果。

这里我们已经不用关注Falchion类对应的bean的id是什么了,因为我们已经定义guanyu bean的autowire属性为"byType"。这个时候guanyu bean会在上下文中寻找和weapon具有相同类型的类对应的bean。
因为Guanyu类的weapon实现Weapon借口,整个上下文中目前只有一个Weapon接口的实现Falchion类,所以以"byType"类型就检测到了falchion bean并将其注入到了guanyu bean的weapon属性中。
但是也会出现一种情况就是检测的时候可能会出现多个相同type的bean,这个时候就不知道要装配那个了。比如,我在新建一个实现Weapon接口的方天画戟类HalBerd:

package com.moonlit.myspring;

public class Halberd implements Weapon {
public void attack() {
System.out.println("halberd is attacking!!!");
}
}

并且在xml文件中声明一个新的halberd bean:

<bean id="halberd" class="com.moonlit.myspring.Halberd" />

在这种情况下就会出错,因为有两个bean满足byType的结果。

这个时候有两种解决办法:
第一种方法是将其中一个bean的primary属性设为false,比如:我们将方天画戟falchion bean的primary属性设为true,以防冠以使用方天画戟(很好奇吕布死了之后,赤兔马归关羽了,方天画戟去哪里了):

  <bean id="falchion" class="com.moonlit.myspring.Falchion"  />
<bean id="halberd" class="com.moonlit.myspring.Halberd" primary="true" />
<bean id="guanyu" class="com.moonlit.myspring.GuanYu" autowire="byType" />

输出结果如下:

GuanYu pick up his weapon.
halberd is attacking!!!

从输出结果中可以看到,关羽没有使用青龙偃月刀,而是使用方天画戟进行攻击了。

注:我看的Spring实战(第3版)上面说bean的默认primary属性默认是true,但是我这里用的是spring 4,根据效果来看primary的默认属性应该是false。
第二种方法是设置其中一个bean的autowire-candidate属性为false,比如:我们将方天画戟的autowire-candidate属性设为false:

  <bean id="falchion" class="com.moonlit.myspring.Falchion"  />
<bean id="halberd" class="com.moonlit.myspring.Halberd" primary="true" autowire-candidate="false" />
<bean id="guanyu" class="com.moonlit.myspring.GuanYu" autowire="byType" />

这个时候测试程序的输出如下:

GuanYu pick up his weapon.
falcon is attacking!

可以看到这个时候关羽又重拾了青龙偃月刀。可以看到,当halberd bean的autowire-candidate属性设为false时,他将不会作为自动装配的竞选bean之一,这个时候虽然halberd的primary属性为true,但是halberd bean没有参与自动装配的竞选,所以自动装配到了falchion。

这种感觉就好像:“隔壁村李小花觊觎我已久,但我是一个要成为海贼王的男人,于是拒绝了她……最终她嫁给了隔壁老王,过上了幸福的生活”。

constructor自动装配

演示constructor之前我需要在在GuanYu类中添加一个构造函数:

    public GuanYu(Weapon weapon) {
this.weapon = weapon;
}

在xml文件中设置guanyu bean的autowire属性为constructor:

  <bean id="falchion" class="com.moonlit.myspring.Falchion"  />
<bean id="guanyu" class="com.moonlit.myspring.GuanYu" autowire="constructor" />

输出结果如下:

GuanYu pick up his weapon.
falcon is attacking!

实现了自动装配。

最佳自动装配

书上说是将autowire属性设为autodetect,但是我发现在我使用的spring 4(我看的书是spring 3)版本中没有autodetect,autowire属性只有byName,byType,constructor,default,no这些属性。

默认自动装配

可以在beans标签中添加default-autowire属性来设置默认自动装配策略,如:在beans标签中添加default-autowire="byType"设置默认自动装配策略为byType自动装配。

混合使用自动装配和显示装配

为了演示这个效果,我为Guanyu类添加了一个String成员变量name,虽然关羽就叫关羽,但是人家称呼他的时候还是会称呼他云长之类的。新定义的GuanYu类如下:

package com.moonlit.myspring;

public class GuanYu implements Hero {
private String name;
private Weapon weapon;
// public GuanYu(String name, Weapon weapon) {
// this.name = name;
// this.weapon = weapon;
// }
public void perform() {
System.out.println(name + " pick up his weapon.");
weapon.attack();
}
public Weapon getWeapon() {
return weapon;
}
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

(这里我注释掉了GuanYu类的构造函数。)

一个完全显示装配的例子如下:

  <bean id="falchion" class="com.moonlit.myspring.Falchion"  />
<bean id="guanyu" class="com.moonlit.myspring.GuanYu">
<property name="name" value="Guan Yun Chang" />
<property name="weapon" ref="falchion" />
</bean>

当然,我们也可以使用显示装配和自动装配结合,显示装配name,自动装配weapon,如下:

  <bean id="falchion" class="com.moonlit.myspring.Falchion"  />
<bean id="guanyu" class="com.moonlit.myspring.GuanYu" autowire="byType">
<property name="name" value="Guan Yun Chang" />
</bean>

具有一样效果的输出。

使用混合装配的最后一个注意事项:当使用constructor自动装配策略时,我们必须让Spring自动装配构造器的所有入参——我们不能混合使用constructor自动装配策略和<constructor-arg>元素。

Spring学习笔记--自动装配Bean属性的更多相关文章

  1. Spring入门(5)-自动装配Bean属性

    Spring入门(5)-自动装配Bean属性 本文介绍如何装配Bean属性. 0. 目录 ByName ByType constructor 默认自动装配 混合使用自动装配和显示装配 1. ByNam ...

  2. [Spring学习笔记 2 ]装配各种类型的属性 map,list,array,null,properties

    一.spring Ioc容器补充(1) Spring Ioc容器 DI(依赖注入): 注入的方式:设值方法注入setter(属性注入)/构造子注入(构造函数传入依赖的对象)/字段注入field(注解) ...

  3. Spring学习总结之装配bean

    1.  XML中显式配置 规范,文件头: <?xml version=”1.0” encoding=”UTF-8”?>            <beans xmlns=http:// ...

  4. Spring学习笔记三:Bean管理

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6775827.html  一:如何使用Spring获取对象 1:定义bean类:要按照注入方式来定义对应的bea ...

  5. Spring学习笔记-高级装配-03

    主要内容: ●Spring profile ●条件化的bean声明 ●自动装配与歧义性 ● Spring表达式语言 本章介绍一些高级的装配技术,可实现更为高级的装配功能. 环境与profile 软件开 ...

  6. Spring学习总结之---装配Bean

    Spring配置的可选方案 前言:Spring容器负责创建应用程序中的bean并通过DI来协调这些对象之间的关系,作为开发人员,你需要告诉Spring容器要创建那些Bean,以哪种方式创建,并且如何将 ...

  7. Spring学习笔记--自动检测

    要使用自动检测,我们需要用到<context:annotation-scan>标签.<context:annotation-scan>元素除了完成与<context:an ...

  8. Spring学习笔记:自动创建Proxy

    为什么需要自动创建Proxy 手动为所有需要代理的类用ProxyFactoryBean创建代理Proxy需要大量的配置. 这样如果需要代理的类很多,配置就很繁琐,而且也不便于xml配置的维护. 因此S ...

  9. 【spring学习笔记二】Bean

    ### bean的三种实例化方式: 1.构造 2.静态工厂 3.实例工厂 其中,工厂就是工厂的概念,工厂函数factor-method会返回她生产出来的产品类. 而构造初始化也可以选择初始化方式和销毁 ...

随机推荐

  1. 抽取、转换和装载介绍(三)ETL系统的34个子系统

    这部分对ETL系统的架构中34个关键子系统进行分类.ETL其实可以分为下面四个步骤: 抽取.在ETL环境中从源系统收集原始数据并且在对任何对数据的重要重构发生之前都将数据写入磁盘.子系统1到子系统3都 ...

  2. web应用中文乱码问题的原因分析

    为了让使用Java语言编写的程序能在各种语言的平台下运行,Java在其内部使用Unicode字符集来表示字符,这样就存在Unicode字符集和本地字符集进行转换的过程.当在Java中读取字符数据的时候 ...

  3. contiki rpl

    Linking target: udp-client-temperature.stk3700arm-none-eabi-gcc -Xlinker -Map=udp-client-temperature ...

  4. Thinkphp3.2版本Controller和Action的访问方法

    一.3.2版本以前controller和action的访问方式在3.2版本以前如果Controller=c.Action=a的话,访问规则如下:http://localhost:81/demo1/in ...

  5. C语言 字面量

    在计算机科学中,字面量(literal)是用于表达源代码中一个固定值的表示法(notation). 几乎所有计算机编程语言都具有对基本值的字面量表示,诸如:整数.浮点数以及字符串: 而有很多也对布尔类 ...

  6. php 删除指定文件 glob,unlink

    我用最简单的语句写了一个php删除指定文件 因为一直越级挑战thinkphp,所以突然面对php有点无所适从了... 首先,php的运行机制,是一个语法就搞定了,还是非要用数据库,还是post什么的. ...

  7. 关于Cocos2d-x手机上运行游戏的时候屏幕横屏改竖屏的解决方案

    cocos2d-x打包的时候默认是横屏,如果要改成竖屏,步骤如下: 1.打开项目 2.打开proj.android 3.编辑AndroidManifest.xml 4. 找到这一句android:sc ...

  8. vlc player验证交换机igmp

    使用vlc media player发送多播数据,验证交换机igmp的设置是否成功. 链接 http://peakdrive.com/?p=440 http://www.dasblinkenlicht ...

  9. PNG透明兼容IE6的几种方法(转)

    png 透明针对 IE6 一直是件挺麻烦的事情,使用的方法也是各有不同,大多的原理是用 IE 的滤镜来解决的. 语法: filter:progid:DXImageTransform.Microsoft ...

  10. 学习:List的扁平化 和 拼接

    一.list_to_binary/1的参数:iolist类型的. 二.lists:concat(Things) -> string() Types: Things = [Thing] Thing ...