(四)依赖注入

依赖注入(Dependency Injection,DI)。

  • 依赖 : 指Bean对象的创建依赖于Spring容器
  • 注入 : 指Bean对象中的属性 , 由容器来设置和装配

注入的三种方式:

构造器注入(有参无参)、setter注入、注解注入(自动装配)

1、构造器注入

默认情况下都是通过无参构造器注入,因为User类中存在隐式的无参构造方法,容器配置如下

    <bean id="user" class="com.alan.pojo.User">
        <property name="name" value="name from bean"/>
    </bean>

而当User类中重载了有参构造方法时,则必须通过有参构造方法注入(同c命名空间注入) 。如下所示

User类

public class User{
    private String name;
    
    public User(String name){
        this.name = name;
    }
}

spring容器配置

<!-- 第一种根据index参数下标设置 -->
<bean id="user" class="com.alan.pojo.User">
    <!-- index指构造方法 , 下标从0开始 -->
    <constructor-arg index="0" value="alan"/>
</bean>

<!-- 第二种根据参数名字设置 -->
<bean id="user" class="com.alan.pojo.User">
    <!-- name指参数名 -->
    <constructor-arg name="name" value="alan"/>
</bean>

<!-- 第三种根据参数类型设置 -->
<bean id="user" class="com.alan.pojo.User">
    <constructor-arg type="java.lang.String" value="alan"/>
</bean>

 

引入p命名空间

xmlns:p="http://www.springframework.org/schema/p"
<!--P(属性: properties)命名空间 , 属性依然要设置set方法-->
    <bean id="userp" class="com.alan.pojo.User" p:name="alan" p:age="18"/>


2、setter注入*

要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型 , 没有set方法 , 是 is 

set示例:

public class UserServiceImpl implements UserService {
    private UserDao userDao;
    // 利用set实现
    public void setUserDao(UserDao userDao) {

        this.userDao = userDao;
    }

    public void getUser() {
        userDao.getUser();
    }
}

 

新建student类,并生成相应set方法

    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;

 

对于不同类型,在xml中的注入

<bean id="addr" class="com.alan.pojo.Address">
    <property name="address" value="上海"/>
</bean>

<bean id="student" class="com.kuang.pojo.Student">
    <property name="name" value="小明"/>
    <property name="address" ref="addr"/><!-- bean注入-->

    <property name="books">
        <array>
            <value>西游记</value>
            <value>红楼梦</value>
            <value>水浒传</value>
        </array>
    </property>

    <property name="hobbys">
    <list>
        <value>听歌</value>
        <value>看电影</value>
        <value>爬山</value>
    </list>
    </property>

  <property name="card">
      <map>
          <entry key="中国邮政" value="456456456465456"/>
          <entry key="建设" value="1456682255511"/>
      </map>
  </property>

  <property name="games">
      <set>
          <value>LOL</value>
          <value>BOB</value>
          <value>COC</value>
      </set>
  </property>

  <property name="wife"><null/></property>

  <property name="info">
      <props>
          <prop key="学号">20190604</prop>
          <prop key="性别">男</prop>
          <prop key="姓名">小明</prop>
      </props>
  </property>

</bean>

 

3、自动装配、注解注入

自动装配

(1) 按名称的自动装配

<bean id="user" class="com.alan.pojo.User" autowire="byName">
    <property name="name" value="alan"/>
</bean>

小结:

当一个bean节点带有 autowire byName的属性时。

  1. 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。
  2. 去spring容器中寻找是否有此字符串名称id的对象。
  3. 如果有,就取出注入;如果没有,就报空指针异常。

(2)按类型的自动装配

使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。

测试:

将user的bean配置修改一下 : autowire="byType",并添加一个相同类型的bean

<bean id="dog" class="com.alan.pojo.Dog"/>
<bean id="cat" class="com.alan.pojo.Cat"/>
<bean id="cat2" class="com.alan.pojo.Cat"/>

<bean id="user" class="com.alan.pojo.User" autowire="byType">
    <property name="str" value="alan"/>
</bean>

此时报错:NoUniqueBeanDefinitionException

删掉cat2,将cat的bean名称改掉!测试!因为是按类型装配,所以并不会报异常,也不影响最后的结果。甚至将id属性去掉,也不影响结果。

 

注解注入

注解注入需要对容器进行一些配置

引入相关约束文件头

xmlns:context="http://www.springframework.org/schema/context"

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd

开启注解支持

<context:annotation-config/>

 

@Autowired

  • @Autowired是按类型自动转配的,不支持id匹配。
  • 需要导入 spring-aop的包!

将User类中的set方法去掉,使用@Autowired注解

public class User {
    @Autowired
    private Cat cat;
    @Autowired
    private Dog dog;
    private String str;

    public Cat getCat() {
        return cat;
    }
    public Dog getDog() {
        return dog;
    }
    public String getStr() {
        return str;
    }
}

此时配置文件内容

<context:annotation-config/>

<bean id="dog" class="com.alan.pojo.Dog"/>
<bean id="cat" class="com.alan.pojo.Cat"/>
<bean id="user" class="com.alan.pojo.User"/>

 

@Autowired(required=false) 说明:

false,对象可以为null;true,对象必须存对象,不能为null。默认为true。

 

@Qualifier

  • @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配
  • @Qualifier不能单独使用。

配置文件修改内容,保证类型存在对象。且名字不为类的默认名字!

<bean id="dog1" class="com.alan.pojo.Dog"/>
<bean id="dog2" class="com.alan.pojo.Dog"/>
<bean id="cat1" class="com.alan.pojo.Cat"/>
<bean id="cat2" class="com.alan.pojo.Cat"/>

没有加Qualifier测试,直接报错,在属性上添加Qualifier注解

@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
@Qualifier(value = "dog2")
private Dog dog;

 

@Resource

  • @Resource如有指定的name属性,先按该属性进行byName方式查找装配;
  • 其次再进行默认的byName方式进行装配;
  • 如果以上都不成功,则按byType的方式自动装配。
  • 都不成功,则报异常。

实体类User

public class User {
    //如果允许对象为null,设置required = false,默认为true
    @Resource(name = "cat2")
    private Cat cat;
    @Resource
    private Dog dog;
    private String str;
}

容器配置文件

<bean id="dog" class="com.alan.pojo.Dog"/>
<bean id="cat1" class="com.alan.pojo.Cat"/>
<bean id="cat2" class="com.alan.pojo.Cat"/>
<bean id="user" class="com.alan.pojo.User"/>

测试成功

删除cat2

<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>

User中不指定name

@Resource
private Cat cat;
@Resource
private Dog dog;

测试成功

结论:先进行byName查找,失败;再进行byType查找

 

小结:

@Autowired 根据类型自动装配,效果同byType,如果这些类的类型都相同,此时就需要使用@Qualifier明确指定使用哪个类,

@Autowired和@Qualifier(value=“xx”)一起使用 则根据指定的名称自动装配,效果同byName

@Resource,可以通过类型也可以通过名称自动装配,如果指定名称,则优先通过指定的名称装配,默认通过byName装配,再通过byType装配

posted @ 2020-02-03 16:40  Alan*Chen  阅读(175)  评论(0编辑  收藏  举报