【Spring】Spring对IoC的实现和依赖注入专题

简介: 【Spring】Spring对IoC的实现和依赖注入专题

1. 依赖注入:

1.1 set注入:

  • 基于set方法实现的, 底层会通过反射机制调用属性对应的set方法然后给属性赋值
  • 这种方式要求属性必须对外提供set方法
  • set注入的核心实现原理: 通过反射机制调用set方法来给属性赋值, 让俩个对象之间产生关系
// xml
<!-- 配置userDao    -->
<bean id="userDaoBean" class="com.powernode.bean.UserDao"/>
<!-- 配置vipDao    -->
<bean id="vipDaoBean" class="com.powernode.bean.VipDao"/>
<!-- 配置User   -->
<bean id="userBean" class="com.powernode.bean.User">
  <!-- 想让Spring调用对应的set方法, 需要配置property标签
  name属性怎么知道值: set方法的方法名, 去掉set, 然后把剩下的首字母小写
  ref翻译为引用, ref后面指定的是要注入的bean的id  -->
  <property name="userDao" ref="userDaoBean"/>
  <property name="vipDao" ref="vipDaoBean"/>
</bean>
// User类
public class User {
    private UserDao userDao;
    private VipDao vipDao;
    public void setVipDao(VipDao vipDao) {
        this.vipDao = vipDao;
    }
    // set注入, 必须提供一个set方法
    // Spring容器会调用这个set方法, 来给userDao属性赋值
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public void saveUser(){
        userDao.saveId();
        vipDao.save();
    }
}
// @Test
public void setDI(){
    ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
    User userBean = ctx.getBean("userBean", User.class);
    userBean.saveUser();
}

1.2 构造注入:

  • 核心原理: 调用构造方法来给属性赋值
  • set注入是在对象构建好了之后调用set方法来完成赋值, 构造注入是在对象实例化的过程中赋值的
// xml
<bean id="userDaoBean" class="com.powernode.bean.UserDao"/>
<bean id="vipDaoBean" class="com.powernode.bean.VipDao"/>
<!-- 构造注入3种方式   -->
<bean id="customerBean" class="com.powernode.bean.Customer">
    <!-- 指定构造方法的第一个参数, 下标是0 -->
    <constructor-arg index="0" ref="userDaoBean"/>
    <!-- 指定构造方法的第二个参数, 下标是1 -->
    <constructor-arg index="1" ref="vipDaoBean"/>
    <!-- 根据构造方法参数的名字进行注入 -->
    <constructor-arg name="userDao" ref="userDaoBean"/>
    <constructor-arg name="vipDao" ref="vipDaoBean"/>
    <!-- 这种方式实际上是根据类型进行注入, Spring会自动根据类型来判断把ref注入给哪个参数-->
    <constructor-arg ref="userDaoBean"/>
    <constructor-arg ref="vipDaoBean"/>
</bean>
// Customer类
public class Customer {
    private UserDao userDao;
    private VipDao vipDao;
    public Customer(UserDao userDao, VipDao vipDao) {
        this.userDao = userDao;
        this.vipDao = vipDao;
    }
    public void insert(){
        userDao.saveId();
        vipDao.save();
    }
}
// @Test
public void constructorDI(){
    ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
    Customer customerBean = ctx.getBean("customerBean", Customer.class);
    customerBean.insert();
}

2. set注入专题:

2.1 注入外部Bean:

// xml
<bean id="orderDaoBean" class="com.powernode.bean.dao.OrderDao"/>
<bean id="orderBean" class="com.powernode.bean.Order">
    // 使用ref属性来引入, 这就是注入外部bean
    <property name="orderDao" ref="orderDaoBean"/>
</bean>
// Order类
public class Order {
    private OrderDao orderDao;
    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }
    public void generate(){
        orderDao.insert();
    }
}

2.2 注入内部Bean:

// xml
<bean id="orderBean2" class="com.powernode.bean.Order">
    <property name="orderDao">
        <!-- 在property标签中使用嵌套的bean标签, 这就是内部bean -->
        <bean class="com.powernode.bean.dao.OrderDao"/>
    </property>
</bean>
// Order类
public class Order {
    private OrderDao orderDao;
    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }
    public void generate(){
        orderDao.insert();
    }
}

2.3 注入简单类型:

简单类型有哪些:

  • 8 种基本类型和8种包装类型
  • 枚举
  • String字符串
  • 数字
  • 日期(java.util.Date), 在实际的开发中, 一般不会把Date当做简单类型, 一般采用ref给Date类型的属性赋值
  • 时间时区类型
  • URI
  • URL
  • 语言类
  • Class类
// xml
<bean id="peopleBean" class="com.powernode.bean.People">
    // 如果是给简单类型赋值, 就不能使用ref, 需要使用value
    <property name="name" value="二狗"/>
    <property name="age" value="16"/>
    <property name="classId" value="1"/>
</bean>
// People类
public class People {
    private String name;
    private int age;
    private int classId;
    public void setName(String name) {this.name = name;}
    public void setAge(int age) {this.age = age;}
    public void setClassId(int classId) {this.classId = classId;}
    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", classId=" + classId +
                '}';
    }
}
// @Test
public void setDI3(){
    ApplicationContext ctx = new ClassPathXmlApplicationContext("set-DI.xml");
    People peopleBean = ctx.getBean("peopleBean", People.class);
    System.out.println(peopleBean);
}

2.4 注入数组:

  • 基本类型和非基本类型的数组注入, 如下:
// xml
<bean id="friend1" class="com.powernode.bean.Friend">
  <property name="name" value="小北"/>
</bean>
<bean id="friend2" class="com.powernode.bean.Friend">
  <property name="name" value="小爱"/>
</bean>
<bean id="friend3" class="com.powernode.bean.Friend">
  <property name="name" value="小花"/>
</bean>
<bean id="stu" class="com.powernode.bean.Student">
  // 这个数组当中的元素类型是String简单类型
    <property name="stus">
        <array>
            <value>"张三"</value>
            <value>"李四"</value>
            <value>"王二蛋"</value>
            <value>"大锤"</value>
        </array>
    </property>
  // 这个数组当中的类型就不是简单类型
    <property name="friends">
        <array>
            <ref bean="friend1"/>
            <ref bean="friend2"/>
            <ref bean="friend3"/>
        </array>
    </property>
</bean>
// Student类
public class Student {
    private String[] stus;
    private Friend[] friends;
    public void setStus(String[] stus) {this.stus = stus;}
    public void setFriends(Friend[] friends) {this.friends = friends;}
    @Override
    public String toString() {
        return "Student{" +
                "stus=" + Arrays.toString(stus) +
                ", friends=" + Arrays.toString(friends) +
                '}';
    }
}
// Friend类
public class Friend {
    private String name;
    public void setName(String name) {this.name = name;}
    @Override
    public String toString() {
        return "Friend{" +
                "name='" + name + '\'' +
                '}';
    }
}
// @Test
public void setDI5(){
  ApplicationContext ctx = new ClassPathXmlApplicationContext("set-DI.xml");
  Student stu = ctx.getBean("stu", Student.class);
  System.out.println(stu);
}

2.5 注入List集合和Set集合:

  • 简单类型
// xml
<bean id="people" class="com.powernode.bean.People">
    <property name="names">
      <list> // list集合有序可重复
            <value>张三</value>
            <value>达尔</value>
            <value>溜达</value>
            <value>张三</value>
            <value>张三</value>
      </list>
    </property>
    <property name="addrs">
      <set> // set集合无序不可重复
            <value>张二</value>
            <value>达</value>
            <value>溜达</value>
      </set>
    </property>
</bean>
// People类
public class People {
    private List<String> names;
    private Set<String> addrs;
    public void setNames(List<String> names) {this.names = names;}
    public void setAddrs(Set<String> addrs) {this.addrs = addrs;}
    @Override
    public String toString() {
        return "People{" +
                ", names=" + names +
                ", addrs=" + addrs +
                '}';
    }
}
// @Test
public void setDI5(){
  ApplicationContext ctx = new ClassPathXmlApplicationContext("set-DI.xml");
  People people = ctx.getBean("people", People.class);
  System.out.println(people);
}

2.6 注入Map集合和properties:

  • Properties本质上也是一个Map集合
  • Properties的父类HashTable, HashTable实现了Map接口
  • 虽然这个也是Map集合, 但是和Map的注入方式不完全一样
  • Properties的key和value只能是String类型
// xml
<bean id="people" class="com.powernode.bean.People">
    <property name="phones"> // 注入map集合
        <map>
            <entry key-ref="" value-ref=""/> // 如果key和value不是简单类型就用这个
            <entry key="1" value=".."/>
            <entry key="2" value=".."/>
            <entry key="3" value=".."/>
        </map>
    </property>
    <property name="properties"> // 注入properties属性类对象
        <props>
            <prop key="..">...</prop>
            <prop key="..">...</prop>
            <prop key="..">...</prop>
        </props>
    </property>
</bean>
// People类
public class People {
    private Map<Integer,String> phones;
    private Properties properties;
    public void setPhones(Map<Integer, String> phones) {this.phones = phones;}
    public void setProperties(Properties properties) {this.properties = properties;}
    @Override
    public String toString() {
        return "People{" +
                "phones=" + phones +
                ", properties=" + properties +
                '}';
    }
}
// @Test
public void setDI5(){
  ApplicationContext ctx = new ClassPathXmlApplicationContext("set-DI.xml");
  People people = ctx.getBean("people", People.class);
  System.out.println(people);
}

2.7 注入null和空字符串:

  • 注入空字符串使用: 或者value=""
// xml
<bean id="dog" class="com.powernode.bean.Dog">
    // 注入空字符串的第一种方式
    <property name="name">
      <value/>
    </property>
    // 注入空字符串的第二种方式
    <property name="age" value=""/>
</bean>
// Dog类
public class Dog {
    private String name;
    private int age;
    public void setName(String name) {this.name = name;}
    public void setAge(int age) {this.age = age;}
    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
// @Test
public void setEmpty(){
    ApplicationContext ctx = new ClassPathXmlApplicationContext("set-DI.xml");
    Dog dog = ctx.getBean("dog", Dog.class);
    System.out.println(dog);
} 
  • 注入null使用: 或者不为该属性赋值
// xml
<bean id="dog" class="com.powernode.bean.Dog">
    // 不给属性注入, 属性的默认值就是null
    // <property name="name" value=""/>
    // 手动注入null
    <property name="age">
      <null/>
    </property>
</bean>

2.8 注入特殊字符:

a92a3a15a41140cdb00bae283cb5036e.png

// xml
<bean id="math" class="com.powernode.bean.Dog">
    // 第一种方案
    <property name="result" value="2 < 3"/>
    // 第二种方案
    <property name="result">
      // 只能使用value标签
      <value><![CDATA[2 < 3]]></value>
    </property>
</bean>

3. 引入外部的属性配置文件:

引入外部的properties文件

  • 第一步: 引入context命名空间
  • 第二步: 使用标签context: property-placeholder的location属性来指定属性配置文件的路径
  • location默认从类的根路径下开始加载资源
// xml
<context: property-placeholder location="jdbc.properties"/>
// 配置数据源
<bean id="ds" class="com....jdbc.MyDataSource">
    // 怎么取值呢? ${key}
    <property name="driver" value="${jdbc.driverClass}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>
// jdbc.properties
jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring6
jdbc.username=root
jdbc.password=123


相关文章
|
26天前
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
26天前
|
XML Java 数据格式
Spring5入门到实战------6、IOC容器-Bean管理XML方式(自动装配)
这篇文章是Spring5框架的入门教程,详细讲解了IOC容器中Bean的自动装配机制,包括手动装配、`byName`和`byType`两种自动装配方式,并通过XML配置文件和Java代码示例展示了如何在Spring中实现自动装配。
Spring5入门到实战------6、IOC容器-Bean管理XML方式(自动装配)
|
27天前
|
XML Java 数据格式
Spring5入门到实战------2、IOC容器底层原理
这篇文章深入探讨了Spring5框架中的IOC容器,包括IOC的概念、底层原理、以及BeanFactory接口和ApplicationContext接口的介绍。文章通过图解和实例代码,解释了IOC如何通过工厂模式和反射机制实现对象的创建和管理,以及如何降低代码耦合度,提高开发效率。
Spring5入门到实战------2、IOC容器底层原理
|
26天前
|
XML Java 数据格式
Spring5入门到实战------8、IOC容器-Bean管理注解方式
这篇文章详细介绍了Spring5框架中使用注解进行Bean管理的方法,包括创建Bean的注解、自动装配和属性注入的注解,以及如何用配置类替代XML配置文件实现完全注解开发。
Spring5入门到实战------8、IOC容器-Bean管理注解方式
|
27天前
|
Java Spring 容器
建模底层逻辑问题之以Spring IOC容器为例,使用因果法建模,如何操作
建模底层逻辑问题之以Spring IOC容器为例,使用因果法建模,如何操作
|
29天前
|
安全 Java 开发者
Java 新手入门:Spring 两大利器IoC 和 AOP,小白也能轻松理解!
Java 新手入门:Spring 两大利器IoC 和 AOP,小白也能轻松理解!
27 1
|
29天前
|
XML Dubbo Java
Spring之Ioc容器
该文章主要介绍了Spring框架中的IoC(Inversion of Control,控制反转)容器,包括IoC容器的概念、IoC容器在Spring中的实现以及IoC容器的基础包等内容。
Spring之Ioc容器
|
11天前
|
Java Spring 容器
彻底改变你的编程人生!揭秘 Spring 框架依赖注入的神奇魔力,让你的代码瞬间焕然一新!
【8月更文挑战第31天】本文介绍 Spring 框架中的依赖注入(DI),一种降低代码耦合度的设计模式。通过 Spring 的 DI 容器,开发者可专注业务逻辑而非依赖管理。文中详细解释了 DI 的基本概念及其实现方式,如构造器注入、字段注入与 setter 方法注入,并提供示例说明如何在实际项目中应用这些技术。通过 Spring 的 @Configuration 和 @Bean 注解,可轻松定义与管理应用中的组件及其依赖关系,实现更简洁、易维护的代码结构。
15 0
|
1月前
|
设计模式 自然语言处理 Java
简单了解下Spring中的各种Aware接口实现依赖注入
在Spring框架中,Aware接口是一组用于提供特定资源或环境信息的回调接口。这些接口被设计用来允许Bean获取对Spring容器或其他相关资源的引用,并在需要时进行适当的处理。
20 2
|
22天前
|
自然语言处理 Java 开发者
简单了解下Spring中的各种Aware接口实现依赖注入
【8月更文挑战第21天】在Spring框架中,Aware接口系列是一种特殊的机制,它允许Bean在初始化过程中获取到Spring容器或容器中的特定资源,从而实现了更加灵活和强大的依赖注入方式。本文将围绕Spring中的各种Aware接口,详细探讨它们如何帮助开发者在工作和学习中更好地实现依赖注入。
35 0