全网疯传的Spring学习笔记【注入】,看完我也想写一个了!

举报
XiaoLin_Java 发表于 2022/01/31 17:27:57 2022/01/31
【摘要】 三、注入 3.1、什么是注入    注入是指 Spring 创建对象的过程中,将对象依赖属性通过配置设值给该对象。 3.2、为什么需要注入    通过编码的方式(setXxx),为成员变量进行赋值,存在耦合。 3.3、注入的方式set注入:其类必须提供对应 setter 方法。构造器注入:利用构造器进行注入。 3.4、set注入package com.domain;/** * @autho...

三、注入

3.1、什么是注入

    注入是指 Spring 创建对象的过程中,将对象依赖属性通过配置设值给该对象。

3.2、为什么需要注入

    通过编码的方式(setXxx),为成员变量进行赋值,存在耦合。

3.3、注入的方式

  1. set注入:其类必须提供对应 setter 方法。
  2. 构造器注入:利用构造器进行注入。

3.4、set注入

package com.domain;

/**
 * @author Xiao_Lin
 * @date 2021/2/4 15:57
 */
public class Person {
  private String username;
  private Integer password;


  @Override
  public String toString() {
    return "Person{" +
        "username='" + username + '\'' +
        ", password=" + password +
        '}';
  }

  public Person(String username, Integer password) {
    this.username = username;
    this.password = password;
  }

  public Person() {
  }

  public String getUsername() {
    return username;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public Integer getPassword() {
    return password;
  }

  public void setPassword(Integer password) {
    this.password = password;
  }
}

<bean id="person" class="com.domain.Person">
    <property name="username">
      <value>Xiao_Lin</value>
    </property>
    <property name="password">
      <value>123456</value>
    </property>
  </bean>
/**
  * 用于测试注入
  */
  @Test
  public void testDI(){
    ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
    Person person = application.getBean("person", Person.class);
    System.out.println(person);
  }

3.4.1、set注入的原理图

    Spring通过底层调用对象属性对应的set方法完成对成员变量的赋值操作。

Spring-第 2 页

3.4.2、set注入详解

    针对不同的不同类型的成员变量,我们不可能一直是使用value标签,我们需要嵌套其他的标签,我们将成员变量可能的类型分类两大类:

  1. JDK内置类型。
  2. 用户自定义类型。

image-20200416090518713

3.4.2.1、JDK内置类型

3.4.2.1.1、String+8种基本数据类型

    都直接使用value标签即可

<property name="password">
	<value>123456</value>
</property>
3.4.2.1.2、数组类型

    对于数组类型,我们需要在配置文件中,使用list标签,表明是数组类型,嵌套value标签来进行赋值。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
  private String[] emails;
}

 <property name="emails">
      <list>
        <value>124@qq.com</value>
        <value>456@163.com</value>
      </list>
    </property>
3.4.2.1.3、Set集合

    对于set集合类型,我们需要在配置文件中,使用set标签,表明是set集合类型,嵌套Set泛型中对应的标签来进行赋值。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
 private Set<String> tels;
}

<property name="tels">
      <set>
        <value>123456</value>
        <value>456789</value>
        <value>13579</value>
      </set>
    </property>

   对于set集合由于我们规范了泛型为String,她是8种基本数据类型,所以在set标签中才嵌套value标签。如果没有规定泛型或者说是规定了其他的泛型,set嵌套的标签需要根据具体的情况来具体分析。

3.4.2.1.4、List集合

    对于List集合类型,我们需要在配置文件中,使用list标签,表明是List集合类型,嵌套List泛型中对应的标签来进行赋值。

    list便签中嵌套什么标签,取决于List集合中的泛型。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
 private List<String> address;
}
<property name="address">
      <list>
        <value>sz</value>
        <value>sz</value>
        <value>gz</value>
      </list>
    </property>
3.4.2.1.5、Map集合

    对于Map集合,有一个内部类——Entry,所以我们在配置文件中需要使用的标签是用map标签来嵌套entry标签,里面是封装了一对键值对。我们使用key标签来表示键,里面嵌套键对应的标签,值要根据对应的类型来选择对应的标签。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
 private Map<String,String> qq;
}
    <property name="qq">
      <map>
        <entry>
          <key><value>zs</value></key>
          <value>123456</value>
        </entry>
        <entry>
          <key><value>lisi</value></key>
          <value>456789</value>
        </entry>
      </map>
    </property>
3.4.2.1.6、Properties集合

    Properties类似是特殊的Map,他的keyvalue都必须是String类型。

    在配置文件中,我们使用props标签,里面嵌套prop标签,一个prop就是一个键值对,键写在key属性中,值写在标签内部。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
 private Properties properties;
}
   <property name="properties">
      <props>
        <prop key="username">admin</prop>
        <prop key="password">123456</prop>
      </props>
    </property>

3.4.2.2、自定义类型

3.4.2.2.1、第一种注入方式
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Hobby {
  private String name;
}
    <property name="hobby">
      <bean class="com.domain.Hobby"/>
    </property>

    我们可以发现第一种注入方式其实就是在property标签里面写一个bean标签,他的劣势也很明显:

  1. 配置文件代码冗余,我有一万个类需要引用同一个对象的时候,我同一段代码需要写一万次。
  2. 被注入的对象,被多次创建,浪费(JVM)内存资源,因为我每写一个bean标签意味着就创建一个新的对象。
3.4.2.2.2、第二种注入方式

    鉴于第一种注入方式的缺点很明显,我们就需要改进,于是就有了第二种注入方式,这种方式是将我们需要注入的对象提前先创建一份出来,谁需要谁去引用即可。

 <bean> 
	<property name="hobby">
      <ref bean="hobby"/>
    </property>
 </bean>
  <bean id="hobby" class="com.domain.Hobby">
    <property name="name">
      <value>admin</value>
    </property>
  </bean>

3.4.3、set注入的简化写法

3.4.3.1、基于属性的简化

JDK类型注入

    我们可以使用value属性来简化value标签的值,但是只可以简化8种基本数据类型➕Stirng类型的值。

<!--以前的方式-->
<property name="name">
	<value>Xiao_Lin</value>
</property>

<!--简化后的方式-->
<property name="name" value="Xiao_Lin"/>

用户自定义类型的注入

    我们可以使用ref属性来简化ref标签的值.

<!--以前的方式-->
<property name="hobby">
	<ref bean="hobby"/>
</property>

<!--简化后的方式-->
<property name="hobby" ref="hobby"/>

3.4.3.2、基于p命名空间的简化

    我们可以发现,bean标签的很多值都是重复且冗余的,于是可以使用p命名空间来进行简化。

<!--内置数据类型-->
<bean id="person" class="com.domain.Person" p:username="zs" p:password="123456" />

<!--用户自定义类型-->
<bean id="hobbyBean" class="com.domain.Hobby"></bean>

<bean id="hobby" class="com.domain.Person" p:hobby-ref="hobbyBean"

3.5、构造注入

    Spring调用构造方法,通过配置文件为成员变量赋值。如果要使用构造注入,必须提供有参的构造方法。

   构造注入使用的标签是constructor-arg标签,一个构造参数就是一对constructor-arg标签。顺序和个数都必须和构造参数一样。

   当出现构造方法重载的时候,我们可以通过控制constructor-arg的个数来进行控制。如果出现构造参数个数相同的重载的时候(如第一个构造方法是给name赋值,第二个构造方法给type赋值),我们需要用type属性来指定类型。

@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Hobby {
  private String name;
  private String type;
}

<bean id="hobbyBean" class="com.domain.Hobby">
    <constructor-arg>
      <value>running</value>
    </constructor-arg>
    <constructor-arg>
      <value>dayily</value>
    </constructor-arg>
  </bean>
/**
  * 用于测试构造注入
  */
  @Test
  public void testDI2(){
    ClassPathXmlApplicationContext cxt =
        new ClassPathXmlApplicationContext("/applicationContext.xml");
    Hobby hobbyBean = cxt.getBean("hobbyBean", Hobby.class);
    System.out.println(hobbyBean);
  }

3.6、注入总结

image-20200416155620897

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。