三、DI 依赖注入学习总结

本文详细介绍了Spring框架中的依赖注入机制,包括构造函数注入和Setter方法注入,这两种方式可通过XML配置或注解实现。重点讨论了Setter方法注入,并展示了如何注入复杂类型和集合类型数据。此外,还提到了JavaProperties和C/P命名空间注入的扩展知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



一、依赖注入



        依赖注入(Dependency Injection,DI)是 Spring 框架的核心特性之一,也是 Spring 实现控制反转(Inversion of Control,IoC)的重要手段。
       依赖注入可以帮助我们解耦应用程序中的各个组件,使得这些组件可以更加灵活地组合和重用。


       要理解什么是依赖注入,就要先知道什么是依赖。依赖就是当我们创建了两个类,A类和B类,当我们在A类中创建了B类的实例,也就是在A类中 new B类的对象了。因为A类是要使用B类中的某些属性,所以这时候A类就依赖与B类。但是这种写法的耦合性十分严重,因为如果B类中的属性发生变化,那么引用B类实例的A类也会受到影响,所以出现了IoC容器,将实例的创建与管理交给Spring IoC容器,在通过依赖注入来实现控制反转,达到解耦的目的。
  • 依赖注入可以注入的类型

    • 基本类型和String字符串

    • 其他 bean类型(在配置文件中或者注解配置过的bean)。

    • 复杂类型/集合类型。



  • 实现依赖注入的方式: 在JDK5.0之前,实现依赖注入的方式有构造函数注入、Setter 方法注入。下面是通过 Char GPT 查询的依赖注入的注入方式相关文档

           在 Spring 框架中,可以通过构造函数注入和 Setter 方法注入来实现依赖注入,并通过 XML 配置文件或注解的方式来配置依赖关系。

            构造函数注入:构造函数注入是一种最常见的依赖注入方式。在构造函数注入中,我们通过构造函数将依赖关系注入到目标对象中。例如,我们可以在构造函数中声明一个接口类型的参数,然后在 Spring 容器中配置该接口的具体实现类,Spring 容器会自动将该实现类注入到构造函数中。
            Setter 方法注入:Setter 方法注入是另一种常见的依赖注入方式。在 Setter 方法注入中,我们通过 Setter 方法将依赖关系注入到目标对象中。例如,我们可以在目标对象中声明一个接口类型的属性,并提供一个 Setter 方法,然后在 Spring 容器中配置该接口的具体实现类,Spring 容器会自动调用 Setter 方法,将该实现类注入到目标对象中。

           无论是构造函数注入还是 Setter 方法注入,Spring 框架都可以通过 XML 配置文件或注解的方式来实现依赖注入。在 XML 配置文件中,我们可以通过 标签来声明目标对象和依赖关系,并通过 ref 属性来指定依赖关系的具体实现类。



1.1 构造函数注入


  • 使用构造函数注入: 当我们通过配置文件配置指定的类时,也就是Bean,Spring 会找到该类的构造方法,通过构造方法给成员变量赋值,这个注入过程完全由 Spring控制。

    • 代码实例:实例一:二、Spring 控制反转(IOC)学习总结中4.4章节

      • 实例二:创建一个子模块,在子模块中创建 User 实体类,不添加Set、get方法,创建有参构造和toString()

        	public class User {
        	    private String str;
        	    private String age;
        	    private String name;
        	    
        	    public User(String name,String str,String age){
        	        this.name = name;
        	        this.str = str;
        	        this.age = age;
        	    }
        	    public void show(){
        	        System.out.println("name:" + name);
        	        System.out.println("age:" + age);
        	        System.out.println("str:" + str);
        	    }
        	}
        
      • 创建 Beans.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
        		        https://www.springframework.org/schema/beans/spring-beans.xsd">
        		
        		    <bean id="user" class="com.sys.dto.User">
        		        <constructor-arg index="1" value="在慵懒的生活中学习Java"/>
        		        <constructor-arg name="name" value="姚青"/>
        		        <constructor-arg type="java.lang.String" value="24"/>
        		    </bean>
        		
        		</beans>
        
      • 创建 MyTest

        	public class MyTest {
        	    public static void main(String[] args) {
        	        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        	        User user = (User) context.getBean("user");
        	        user.show();
        	    }
        	}
        
      • 运行结果
        在这里插入图片描述





1.2 Setter 方法注入(重点掌握)


  • 使用 Setter 方法注入: 通过反射调用set ()进行注入,所以要注入的实体类属性要有相对应的set方法

    • 依赖注入本质上就是Set注入,底层是通过Set()来实现的。

      • 依赖:bean对象的创建依赖于容器!

      • 注入:bean对象中的所有属性,由容器来注入!





1.2.1 通过 Set 注入复杂类型和集合类型数据



  • ref 标签: 对应ref属性,该标签name属性的属性值为另一个bean标签id或name属性的属性值;

  • array 标签: 为数组类型参数赋值;

  • value 标签: 对应value属性,用于设置基本数据类型或String类型的参数值;

  • list 标签: 为数组或List类型的参数赋值

  • set 标签: 为Set集合类型参数赋值

  • map 标签: 为Map集合类型参数赋值

  • props 标签: 为Properties类型的参数赋值



  • 通过 Set 注入复杂类型和集合类型数据

    • 创建一个子模块,与子模块中创建对应路径,创建 UserInfo 实体类

      public class UserInfo {
      
          // 使用Set注入的方式对各种类型数据进行注入
          private String name;// 字符串
          private Address address;// 引用类型
          private String[] books;// 数组类型
          private List<String> hobbys; // List 集合类型
          private Map<String, String> card;// Map 集合类型
          private Set<String> games;// Set 集合类型
          private String wife;
          private Properties info;// 引用类型
      
          public String getName() {return name;}
      
          public void setName(String name) {this.name = name;}
      
          public Address getAddress() {return address; }
      
          public void setAddress(Address address) {this.address = address;}
      
          public String[] getBooks() {return books;}
      
          public void setBooks(String[] books) {this.books = books;}
      
          public List<String> getHobbys() {return hobbys;}
      
          public void setHobbys(List<String> hobbys) {this.hobbys = hobbys;}
      
          public Map<String, String> getCard() {return card;}
      
          public void setCard(Map<String, String> card) {this.card = card;}
      
          public Set<String> getGames() {return games;}
      
          public void setGames(Set<String> games) {this.games = games;}
      
          public String getWife() {return wife;}
      
          public void setWife(String wife) {this.wife = wife; }
      
          public Properties getInfo() {return info;}
      
          public void setInfo(Properties info) {this.info = info; }
      
          @Override
          public String toString() {
              return "Student{" +
                      "name='" + name + '\'' +
                      ", address=" + address +
                      ", books=" + Arrays.toString(books) +
                      ", hobbys=" + hobbys +
                      ", card=" + card +
                      ", games=" + games +
                      ", wife='" + wife + '\'' +
                      ", info=" + info +
                      '}';
          }
      }
      
    • 创建 Address 实体类

      public class Address {
      
          private String address;
      
          public String getAddress() {return address;}
      
          public void setAddress(String address) {this.address = address;}
      }
      
    • 创建 Beans.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
              https://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <bean id="address" class="com.sys.dto.Address">
              <property name="address" value="该用户来自外太空"/>
          </bean>
      
          <!-- 使用 Set注入复杂类型和集合类型数据 -->
          <bean id="userInfo" class="com.sys.dto.UserInfo">
              
              <!-- 第一种:字符串注入,直接用value注入 -->
              <property name="name" value="姚青"/>
              
              <!-- 第二种:注入引用类型数据,使用ref来注入 -->
              <property name="address" ref="address"/>
              
              <!-- 第三种:注入数组类型数据 -->
              <property name="learnContent">
                  <array>
                      <!-- 注:value注入的数据类型与实体类属性类型一致 -->
                      <value>JAVA</value>
                      <value>Mysql</value>
                      <value>Spring</value>
                      <value>Vue</value>
                  </array>
              </property>
              
              <!-- 第四种:注入 List 集合类型数据 -->
              <property name="hobbys">
                  <list>
                      <value>打游戏</value>
                      <value>在森林公园散步</value>
                      <value>躺在雪地里看天</value>
                  </list>
              </property>
      
              <!-- 第五种:注入Set 集合类型数据 -->
              <property name="games">
                  <set>
                      <value>王者荣耀</value>
                      <value>口袋妖怪</value>
                  </set>
              </property>
      
              <!-- 第六种:注入Map 集合类型数据 -->
              <property name="card">
                  <map>
                      <entry key="education" value="本科"/>
                      <entry key="age" value="24"/>
                  </map>
              </property>
      
              <!-- 第七种:注入 为 NULL 的数据 -->
              <property name="wife">
                  <null/>
              </property>
      
              <!-- 第八种:注入 Properties 类型数据 -->
              <property name="info">
                  <props>
                      <prop key="blogType">优快云</prop>
                      <prop key="blogUrl">https://blog.youkuaiyun.com/shiyu_951/article/details/123269378</prop>
                  </props>
              </property>
          </bean>
      </beans>
      
    • 创建 SetterMyTest 测试类

      public class SetterMyTest {
          public static void main(String[] args) {
              ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
              UserInfo student = (UserInfo) context.getBean("userInfo");
              System.out.println("姓名:" + student.getName());
              System.out.println("住址:" + student.getAddress().getAddress());
              System.out.println("学习内容:" + Arrays.toString(student.getLearnContent()));
              System.out.println("爱好:" + student.getHobbys());
              System.out.println("喜欢的游戏:" + student.getGames());
              System.out.println("身份信息:" + student.getCard());
              System.out.println("是否婚配:" + student.getWife());
              System.out.println("博客信息:" + student.getInfo());
          }
      }
      
    • 运行结果
      在这里插入图片描述

扩展

       Java Properties 是一种用于存储和读取配置文件的数据结构,它继承自 Hashtable 类,可以保存一些键值对的配置信息,例如数据库连接信息、系统参数等。
       Properties 对象中的键和值都是字符串类型的,它提供了一些方法来读取和设置键值对,比如 getProperty()、setProperty()、load()、store() 等方法。




1.3 P & C 命名空间注入(扩展)


官方解释:
在这里插入图片描述

  • 通过C命名空间和P命名空间进行注入

    • 注:不能直接使用命名空间,需要先导入xml约束,才可以使用!

      • C 命名空间引用:xmlns:c=“http://www.springframework.org/schema/c”

      • P 命名空间引用:xmlns:p=“http://www.springframework.org/schema/p”

    • C 命名空间注入: 相当于 property 标签

      • 使用时 Bean 中需要存在有参构造方法
    • P 命名空间注入: 相当于 constructor-args 标签

      • 使用时 Bean 中需要存在无参构造方法
    • 代码实例

      • 实体类

        public class User {
        
            private String name;
            private int age;
        
            public String getName() {
                return name;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        
            public int getAge() {
                return age;
            }
        
            public void setAge(int age) {
                this.age = age;
            }
        
            public User() {
        
            }
        
            public User(String name, int age) {
                this.name = name;
                this.age = age;
            }
        
            @Override
            public String toString() {
                return "User{" +
                        "name='" + name + '\'' +
                        ", age=" + age +
                        '}';
            }
        }
        
        
      • UserBean.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"
               xmlns:c="http://www.springframework.org/schema/c"
               xmlns:p="http://www.springframework.org/schema/p"
               xsi:schemaLocation="http://www.springframework.org/schema/beans
                https://www.springframework.org/schema/beans/spring-beans.xsd">
        
            <!--p命名空间注入,可以直接注入属性的值:property-->
            <bean id="user" class="com.sys.dto.User" p:name="姚青" p:age="24"/>
        
            <!--c命名空间注入,通过构造器注入:constructor-args-->
            <bean id="user2" class="com.sys.dto.User" c:name="姚青2" c:age="10086"/>
        
        </beans>
        
      • 测试类

        public class UserTest {
            public static void main(String[] args) {
                ApplicationContext context = new ClassPathXmlApplicationContext("UserBeans.xml");
                User user = context.getBean("user",User.class);
                System.out.println(user);
                User user2 = context.getBean("user2",User.class);
                System.out.println(user2);
            }
        }
        
      • 运行结果
        在这里插入图片描述




1.4 Bean 的作用域



  • Spring 官网 Bean 的作用域讲解
    在这里插入图片描述

  • 单例(Singleton)作用域:在这种作用域下,容器只会创建一个Bean实例对象,无论该Bean被注入到多少个其它Bean中,它在容器中的实例始终都只有一个。默认情况下,Spring的Bean是单例的。

  • 原型(Prototype)作用域:在这种作用域下,每次请求获取该Bean时,容器都会创建一个新的实例对象。这意味着,对于同一个Bean,可以同时存在多个实例。

  • 其余的request、session、application、这些只能在web开发中使用到!

    • 通过< beans >标签的 scope 属性来控制选择哪种作用域

      • Bean.xml

        <!-- 单例模式 -->
        <bean id="user" class="com.sys.dto.User" c:name="姚青" c:age="24" scope="singleton"/>
        <!-- 原型模式 -->
        <bean id="user2" class="com.sys.dto.User" c:name="姚青Max" c:age="10086" scope="prototype"/>
        
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值