重温Spring笔记3 - 依赖注入

一、概念:

注入依赖对象有手工装配和自动装配两种方式。所谓的装配就是创建应用对象之间的协作关系的行为。

二、手工装配【构造器注入、setter注入(包括P标签的用法)】

1、构造器注入

  • 这里以“歌手唱歌为例子”,Singer类有singerName、age、songName三个属性
  • 创建Singger类,并添加构造函数
public class Singer implements Person {

    private String singerName;
    private int age;
    private String songName;

    public Singer(String singerName, int age, String songName) {
        this.singerName = singerName;
        this.age = age;
        this.songName = songName;
    }

    public void perform(){
        System.out.println("我是歌手"+singerName+",今年"+age+"岁,即将演唱的歌曲是‘"+songName+"’");
    }
}
  • 在配置文件中,用constructor-arg 注入相应的属性

<bean id="singer" class="com.chensr.test.Singer">
    <constructor-arg index="0" type="java.lang.String" value="chensr"></constructor-arg>
    <constructor-arg index="1" type="int" value="18" ></constructor-arg>
    <constructor-arg index="2" type="java.lang.String" value="英雄泪" ></constructor-arg>
</bean>

注:配置文件constructor-arg中的index表示参数的位置,type表示参数类型,value表示参数值。Index、type主要用于防止类中多个构造器匹配混乱的问题。

  • 测试类
public class Test {
    @org.junit.Test
    public void test(){
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring-context.xml");
        Person singer = (Person)ac.getBean("singer");
        singer.perform();
    }
}
  • 运行结果:我是歌手chensr,今年18岁,即将演唱的歌曲是‘英雄泪’

 ----------------------------------------------------------------------------------------------------------------------

  • 上面例子用的是值注入,如果要注入对象,使用的是在constructor-arg的ref属性。例子“歌手不仅唱歌,还表演吉他”。
  • 添加音乐工具类
public interface MusicalInstruments {
    public void perform();
}
  • 建一个Guitar类,实现MusicalInstruments接口
public class Guitar implements MusicalInstruments{
    @Override
    public void perform() {
        System.out.println("吉他表演...");
    }
}
  • 修改Singer类,添加吉他属性
public class Singer implements Person {

    private String singerName;
    private int age;
    private String songName;
    private MusicalInstruments guitar;

    public Singer(String singerName, int age, String songName, MusicalInstruments guitar) {
        this.singerName = singerName;
        this.age = age;
        this.songName = songName;
        this.guitar = guitar;
    }

    public void perform(){
        System.out.println("我是歌手"+singerName+",今年"+age+"岁,即将演唱的歌曲是‘"+songName+"’");
        if(guitar!=null){
            guitar.perform();
        }
    }
}
  • 修改配置文件

<bean id="guitar" class="com.chensr.test.Guitar"></bean>
<bean id="singer" class="com.chensr.test.Singer">
    <constructor-arg index="0" type="java.lang.String" value="chensr"></constructor-arg>
    <constructor-arg index="1" type="int" value="18" ></constructor-arg>
    <constructor-arg index="2" type="java.lang.String" value="英雄泪" ></constructor-arg>
    <constructor-arg index="3" ref="guitar"></constructor-arg>
</bean>

  • 测试输出结果:

  我是歌手chensr,今年18岁,即将演唱的歌曲是‘英雄泪’

  吉他表演...

2、setter注入

  • 修改Singer类,删掉构造方法,并为属性添加setter方法
public class Singer implements Person {
    private String singerName;
    private int age;
    private String songName;
    private MusicalInstruments guitar;

    public void perform(){
        System.out.println("我是歌手"+singerName+",今年"+age+"岁,即将演唱的歌曲是‘"+songName+"’");
        if(guitar!=null){
            guitar.perform();
        }
    }
    public void setSingerName(String singerName) {
        this.singerName = singerName;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setSongName(String songName) {
        this.songName = songName;
    }
    public void setGuitar(MusicalInstruments guitar) {
        this.guitar = guitar;
    }
}
  • 在配置文件中,用property注入相应的属性

<bean id="guitar" class="com.chensr.test.Guitar"></bean>
<bean id="singer" class="com.chensr.test.Singer">
    <property name="singerName" value="chensr"></property>
    <property name="age" value="11"></property>
    <property name="songName" value="英雄泪"></property>
    <property name="guitar" ref="guitar"></property>
</bean>

  • 测试输出结果:

  我是歌手chensr,今年18岁,即将演唱的歌曲是‘英雄泪’

  吉他表演...

3、P标签的引用

  • 引起p标签的命名空间xmlns:p="http://www.springframework.org/schema/p"

l 修改配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd" >

    <bean id="guitar" class="com.chensr.test.Guitar"></bean>
    <bean id="singer" class="com.chensr.test.Singer" p:singerName="chensr" p:age="18" p:songName="英雄泪" p:guitar-ref="guitar">
    </bean>
</beans>

此时运行测试类,已经能得到setter注入一样的运行结果

三、自动装配【byName,byType,constructor和autodetect】

1、byName:把与bean的属性具有相同名字(或者ID)的其他bean自动装配到Bean对应的属性中,如果没有个属性名字相匹配的bean,则该属性不进行装配,如果发现多个,则抛出异常。

  • 比如将Guitar自动装配到Singer中
  • Singer类代码不变
public class Singer implements Person {
    private String singerName;
    private int age;
    private String songName;
    private MusicalInstruments guitar;

    public void perform(){
        System.out.println("我是歌手"+singerName+",今年"+age+"岁,即将演唱的歌曲是‘"+songName+"’");
        if(guitar!=null){
            guitar.perform();
        }
    }
    public void setSingerName(String singerName) {
        this.singerName = singerName;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setSongName(String songName) {
        this.songName = songName;
    }
    public void setGuitar(MusicalInstruments guitar) {
        this.guitar = guitar;
    }
}
  • 修改配置文件类的实例

<bean id="guitar" class="com.chensr.test.Guitar"></bean>
<bean id="singer" class="com.chensr.test.Singer" autowire="byName">
    <property name="singerName" value="chensr"/>
    <property name="age" value="18"/>
    <property name="songName" value="英雄泪"/>
</bean>

  • 测试运行测试类,依旧能够在控制台看到:吉他表演...

2、byType:把与bean的属性具有相同类型的其他bean自动装配到bean的对象属性中,找不到相应类型,则不装配。

3、Constructor:把与bean的构造器入参具有相同类型的其他bean自动装配到bean构造器的对应入参中。

4、autodetect:先尝试constructor自动装配,如果失败,在尝试使用byType进行自动装配。

注:可以在配置文件的beans节点中添加default-autowire属性进行全局配置

<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-4.0.xsd"
       default-autowire="byName" >

 

四、基于注解注入

l Spring支持@Atutowierd、@Inject、@Resource三种注解,使用注解需要使用context命名空间,并配置自动扫描,让spring可以通过注解实例化相应的对象

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!-- 开启注解 -->
    <context:annotation-config/>
    <!-- 自动扫描:使用annotation自动注册bean, 并保证@Required、@Autowired的属性被注入 -->
    <context:component-scan base-package="com.chensr">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />
    </context:component-scan>
</beans>

1、@Atutowierd(默认按类型装配,匹配到多个时按名称装配)

  • 为Guitar添加注解@Component
@Component
public class Guitar implements MusicalInstruments{
    @Override
    public void perform() {
        System.out.println("吉他表演...");
    }
}
  • 为Singer添加相应的注解
@Component
public class Singer implements Person {
    @Value("chensr")          //值注解
    private String singerName;
    @Value("18")
    private int age;
    @Value("英雄泪")
    private String songName;
    @Autowired              //注入注解
    private MusicalInstruments guitar;

    public void perform(){
        System.out.println("我是歌手"+singerName+",今年"+age+"岁,即将演唱的歌曲是‘"+songName+"’");
        if(guitar!=null){
            guitar.perform();
        }
    }

    public void setSingerName(String singerName) {
        this.singerName = singerName;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setSongName(String songName) {
        this.songName = songName;
    }

    public void setGuitar(MusicalInstruments guitar) {
        this.guitar = guitar;
    }
}

注:这里的setter方法可以删掉,只是基于编程习惯将它写上

  • 测试运行测试类,在控制台看到

  我是歌手chensr,今年18岁,即将演唱的歌曲是‘英雄泪’

  吉他表演...

---------------------------------------------------------------------------------------------------------------------- 

注意:

1、@Atutowierd除了可以标注在定义属性的地方,还可以标注在需要装配bean引用的任意地方,比如setter、构造器。但如果只@Atutowierd时,缺点比较大,就是应用中必须只有一个bean合适装配到@Atutowierd标注的属性或参数中,否则就会出错。

  • 解决上面问题,需要用到required属性,该属性默认为true,当将属性设置为false时,当找不到适合的bean时,表示注入NULL值。

    @Autowired (required = false)

  • 此时将Guitar的注解@Component删掉,运行测试类依旧正常运行只是不会打印“吉他表演...” 

2、当匹配到多个时,按名字装配时又匹配不到时,系统会报错

  • 添加Piano类,同样继承MusicalInstruments
@Component
public class Piano implements MusicalInstruments {
    @Override
    public void perform() {
        System.out.println("钢琴表演...");
    }
}
  • 修改Singer属性private MusicalInstruments guitarMusicalInstruments musicalInstruments
@Component
public class Singer implements Person {
    @Value("chensr")          //值注解
    private String singerName;
    @Value("18")
    private int age;
    @Value("英雄泪")
    private String songName;
    @Autowired (required = false)             //注入注解
    private MusicalInstruments musicalInstrument;

    public void perform(){
        System.out.println("我是歌手"+singerName+",今年"+age+"岁,即将演唱的歌曲是‘"+songName+"’");
        if(musicalInstrument!=null){
            musicalInstrument.perform();
        }
    }

    public void setSingerName(String singerName) {
        this.singerName = singerName;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setSongName(String songName) {
        this.songName = songName;
    }

    public void setGuitar(MusicalInstruments musicalInstrument) {
        this.musicalInstrument = musicalInstrument;
    }
}
  • ·运行测试类,会报错:Error creating bean with name 'singer': Unsatisfied dependency expressed through field 'musicalInstrument': No qualifying bean of type
  • 解决这个问题,需要添加@Qualifier注解,比较我现在要注入piano,添加@Qualifier(“piano”)即可
@Component
public class Singer implements Person {
    @Value("chensr")          //值注解
    private String singerName;
    @Value("18")
    private int age;
    @Value("英雄泪")
    private String songName;
    @Autowired (required = false)             //注入注解
    @Qualifier("piano")
    private MusicalInstruments musicalInstrument;

    public void perform(){
        System.out.println("我是歌手"+singerName+",今年"+age+"岁,即将演唱的歌曲是‘"+songName+"’");
        if(musicalInstrument!=null){
            musicalInstrument.perform();
        }
    }

    public void setSingerName(String singerName) {
        this.singerName = singerName;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setSongName(String songName) {
        this.songName = songName;
    }

    public void setGuitar(MusicalInstruments musicalInstrument) {
        this.musicalInstrument = musicalInstrument;
    }
}
  • 运行测试类,控制台打印:

  我是歌手chensr,今年18岁,即将演唱的歌曲是‘英雄泪’

  钢琴表演...

2、@Resource(默认按名称装配,当找不到与名称匹配的bean才会按类型匹配)

  • @Resource有一个name属性,用于按名称装配:@Resource(name = "piano")
  • @Resource是jdk6引入的,不是spring本身自带的

3、@Inject(默认根据类型装配)

  • 该注解没有required属性,所以注解所标注的依赖关系必须存在
  • 提供了@Named用于按名字匹配,跟@Qualifier用法一样

注:现在企业开发,一般都是使用@Atutowierd

 

五、集合类型注入(这里不用注解)

  • Spring提供了set、list、map、properties集合类型的注入方法。如果一个singer想唱几首歌的话,我们可以在Singer类中设置一个songsName属性,并为其生成setter方法

1、set的用法

  • Singer类
public class Singer implements Person {
    private String singerName;
    private int age;
    private Set<String> songsName;
    private MusicalInstruments musicalInstrument;

    public void perform(){
        System.out.println("我是歌手"+singerName+",今年"+age+"岁,即将演唱的歌曲有‘"+ Arrays.asList(songsName)+"’");
        if(musicalInstrument!=null){
            musicalInstrument.perform();
        }
    }
    public void setSingerName(String singerName) {
        this.singerName = singerName;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setSongsName(Set<String> songsName) {
        this.songsName = songsName;
    }
    public void setMusicalInstrument(MusicalInstruments musicalInstrument) {
        this.musicalInstrument = musicalInstrument;
    }
}
  • 配置文件

<bean id="guitar" class="com.chensr.test.Guitar"/>
<bean id="singer" class="com.chensr.test.Singer">
    <property name="singerName" value="chensr"></property>
    <property name="age" value="18"></property>
    <property name="musicalInstrument" ref="guitar"></property>
    <property name="songsName">
        <set>
            <value>英雄泪</value>
            <value>封锁我一生</value>
        </set>
    </property>
</bean>

  • 运行测试类,控制台打印:

  我是歌手chensr,今年18岁,即将演唱的歌曲有‘[[英雄泪, 封锁我一生]]’

  吉他表演...

2、List的用法

  • Singer类
public class Singer implements Person {
    private String singerName;
    private int age;
    private List<String> songsName;
    private MusicalInstruments musicalInstrument;

    public void perform(){
        System.out.println("我是歌手"+singerName+",今年"+age+"岁,即将演唱的歌曲有‘"+ Arrays.asList(songsName)+"’");
        if(musicalInstrument!=null){
            musicalInstrument.perform();
        }
    }
    public void setSingerName(String singerName) {
        this.singerName = singerName;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setSongsName(List<String> songsName) {
        this.songsName = songsName;
    }
    public void setMusicalInstrument(MusicalInstruments musicalInstrument) {
        this.musicalInstrument = musicalInstrument;
    }
}
  • 配置文件

<bean id="guitar" class="com.chensr.test.Guitar"/>
<bean id="singer" class="com.chensr.test.Singer">
    <property name="singerName" value="chensr"></property>
    <property name="age" value="18"></property>
    <property name="musicalInstrument" ref="guitar"></property>
    <property name="songsName">
        <list>
            <value>英雄泪</value>
            <value>封锁我一生</value>
        </list>
    </property>
</bean>

  • 运行测试类,控制台打印:

  我是歌手chensr,今年18岁,即将演唱的歌曲有‘[[英雄泪, 封锁我一生]]’

  吉他表演...

3、map用法

  • Map是基于键值对存值的,这里有它来存放歌名和对应的语言
  • Singer类
public class Singer implements Person {
    private String singerName;
    private int age;
    private Map<String,String> songsName;
    private MusicalInstruments musicalInstrument;

    public void perform(){
        System.out.println("我是歌手"+singerName+",今年"+age+"岁,即将演唱的歌曲有‘"+ Arrays.asList(songsName)+"’");
        if(musicalInstrument!=null){
            musicalInstrument.perform();
        }
    }
    public void setSingerName(String singerName) {
        this.singerName = singerName;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setSongsName(Map<String, String> songsName) {
        this.songsName = songsName;
    }
    public void setMusicalInstrument(MusicalInstruments musicalInstrument) {
        this.musicalInstrument = musicalInstrument;
    }
}
  • 配置文件

<bean id="guitar" class="com.chensr.test.Guitar"/>
<bean id="singer" class="com.chensr.test.Singer">
    <property name="singerName" value="chensr"></property>
    <property name="age" value="18"></property>
    <property name="musicalInstrument" ref="guitar"></property>
    <property name="songsName">
        <map>
            <entry key="英雄泪" value="中文"></entry>
            <entry key="Hear me cry" value="英文"></entry>
        </map>
    </property>
</bean>

  •  运行测试类,控制台打印:

  我是歌手chensr,今年18岁,即将演唱的歌曲有‘[{英雄泪=中文, Hear me cry=英文}]’

  吉他表演...

4、Properties用法(与set相似,键值对必须是String)

  • Singer类
public class Singer implements Person {
    private String singerName;
    private int age;
    private Properties  songsName;
    private MusicalInstruments musicalInstrument;

    public void perform(){
        System.out.println("我是歌手"+singerName+",今年"+age+"岁,即将演唱的歌曲有‘"+ Arrays.asList(songsName)+"’");
        if(musicalInstrument!=null){
            musicalInstrument.perform();
        }
    }
    public void setSingerName(String singerName) {
        this.singerName = singerName;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setSongsName(Properties songsName) {
        this.songsName = songsName;
    }
    public void setMusicalInstrument(MusicalInstruments musicalInstrument) {
        this.musicalInstrument = musicalInstrument;
    }
}
  • 配置文件

<bean id="guitar" class="com.chensr.test.Guitar"/>
<bean id="singer" class="com.chensr.test.Singer">
    <property name="singerName" value="chensr"></property>
    <property name="age" value="18"></property>
    <property name="musicalInstrument" ref="guitar"></property>
    <property name="songsName">
        <props>
            <prop key="英雄泪" >中文</prop>
            <prop key="Hear me cry">英文</prop>
        </props>
    </property>
</bean>

  • 运行测试类,控制台打印:

  我是歌手chensr,今年18岁,即将演唱的歌曲有‘[{英雄泪=中文, Hear me cry=英文}]’

  吉他表演...

5、Util的使用

  • 通过util命名空间将集合定义成一个外部bean,再通过ref引用该集合bean
  • 以Properties为例修改配置文件(添加util命名空间和集合bean)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/util  http://www.springframework.org/schema/util/spring-util-4.0.xsd">

    <util:properties id="properties">
        <prop key="英雄泪" >中文</prop>
        <prop key="Hear me cry">英文</prop>
    </util:properties>

    <bean id="guitar" class="com.chensr.test.Guitar"/>
    <bean id="singer" class="com.chensr.test.Singer">
        <property name="singerName" value="chensr"></property>
        <property name="age" value="18"></property>
        <property name="musicalInstrument" ref="guitar"></property>
        <property name="songsName" ref="properties"></property>
    </bean>
</beans>

  •  运行结果跟上文Properties例子是一样的

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值