0
点赞
收藏
分享

微信扫一扫

Spring IoC(控制反转)、DI(依赖注入)


1. IoC

IoC(Inversion of Control,控制反转) 面向对象的一种设计思想,很多语言的框架都使用了IoC这个设计思想,并非特属于
Spring,其实现为将实例对象交给第三方容器管理,创建实例对象的时候,注入这些实例对象所依赖的实例对象,而不是在内部创建。所谓的内部创建如下所示,连接数据库的DateSource,在默认构造函数直接初始化属性值:

/**
 * @author syrdbt
 * @date 2020-11-15
 */
public class DateSource {

   private String dataBaseUrl;

   private String userName;

   private String password;

    public DateSource() {
    }

    public DateSource() {
        String dateBaseUrl = new String("127.0.0.1:3306");
        String userName = new String("syrdbt");
        String password = new String("syrdbt");
    }
}

使用DateSource如下所示:

public class Main {
    public static void main(String[] args) {
        DataSource dataSource = new DataSource();
    }
}

使用 IoC 之后,你只需定义一个如下的DateSource类:

/**
 * @author syrdbt
 * @date 2020-11-15
 */
public class DateSource {

   private String dataBaseUrl;

   private String userName;

   private String password;

    public DateSource() {
    }

    public DateSource(String dataBaseUrl, String userName, String password) {
        this.dataBaseUrl = dataBaseUrl;
        this.userName = userName;
        this.password = password;
    }
   
}

获取DataSource实例的时候,使用一个管理这个实例的容器工厂去获取,上面实例化的127.0.0.1:3306、syrdbt等信息,在其他地方配置即可,例如XML文件中,容器会去读取XML文件这些配置:

public class Main {
    public static void main(String[] args) {
        // 读取第三方配置中的数据、并将DataSource放入容器之中
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 获取该DataSource实例
        DataSource dataSource = Factor.get("dataSource");
}

2. 依赖注入(DI)

依赖注入(Dependency Injection)是Spring框架实现控制反转的方式。

依赖注入有三种方式:构造函数注入、属性注入 和 接口注入。

2.1 构造函数注入

Service类如下所示。

/**
 * @author syrdbt
 * @date 2020-11-14
 */
public class Service {

   private Mapper mapper;

    public Service(Mapper mapper) {
        this.mapper = mapper;
    }
}

Service 使用构造函数注入 Mapper如下所示:

public static void main(String[] args) {
        // 注入Mapper实例
        Service service = new Service(new Mapper());
    }

2.2 属性注入

Service 类如下所示:

/**
 * @author syrdbt
 * @date 2020-11-14
 */
public class Service {

    private Mapper mapper;

    public void setMapper(Mapper mapper) {
        this.mapper = mapper;
    }
}

使用属性注入如下所示:

public static void main(String[] args) {
        Service service = new Service();
        // 注入Mapper实例
        service.setMapper(new Mapper());
    }

2.3 接口注入

Service 接口如下所示:

/**
 * @author syrdbt
 * @date 2020-11-14
 */
public interface Service {
    void init(Mapper mapper);
}

需要去实现这个接口:

/**
 * @author syrdbt
 * @date 2020-11-14
 */
public class ServiceImpl implements Service {
    
    private Mapper mapper;
    
    @Override
    public void init(Mapper mapper) {
        this.mapper = mapper;
    }
    
}

调用方法注入实例,通过接口注入,需要额外声明接口,增加了类的数量,但效果和属性注入是一样的。

public static void main(String[] args) {
        Service service = new ServiceImpl();
        // 注入Mapper实例
        service.init(new Mapper());
    }

2.4 不使用依赖注入的情况

不使用依赖注入就会导致代码耦合,如下所示。

/**
 * @author syrdbt
 * @date 2020-11-14
 */
public class Service {


    private Mapper mapper;

    public Service() {
        this.mapper = new Mapper();
    }

    public static void main(String[] args) {
        // 无需注入
        Service service = new Service();
    }
}

通过上述四个例子,你会发现依赖注入其实是一个很简单的概念。

3. Spring IoC 中的依赖注入

3.1 Spring IoC 中的依赖注入实例

Spring 支持属性注入和构造注入两种注入方式构建Bean实例。

People 类如下所示,People 就是一个调用者:

package com.study.syrdbt.entity;

/**
 * @author syrdbt
 * @date 2020-10-10
 */
public class People {

    private String name;

    private Integer age;

    public People() {
    }

    public People(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

将 name 和 age 注入到 People 中,可以在 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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 属性注入 -->
    <bean id="syrdbt" class="com.study.syrdbt.entity.People">
        <property name="name" value="syrdbt"></property>
        <property name="age" value="23"></property>
    </bean>

    <!-- 构造器注入 -->
    <bean id="syrdbt1" class="com.study.syrdbt.entity.People">
        <constructor-arg index="0">
            <value>syrdbt</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>233</value>
        </constructor-arg>
    </bean>

</beans>

测试类:

package com.study.syrdbt;

import com.study.syrdbt.entity.People;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author syrdbt
 * @date 2020-10-10
 */
public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        People syrdbt = (People) context.getBean("syrdbt");
        System.out.println(syrdbt.toString());
        People syrdbt1 = (People) context.getBean("syrdbt1");
        System.out.println(syrdbt1.toString());
    }
}

测试结果如下图所示:

Spring  IoC(控制反转)、DI(依赖注入)_属性注入

3.2 Spring 如何使用 xml 文件去注入

第一步:读入XML文件;
第二步:解析XML文件,生成Bean对象,并存放在一个容器中(其实就是一个Map接口,key为xml中的id,value为实例)
第三步:通过id去访问这些Bean对象。

Spring 的内部实现当然不是上面三步那么简单,上面只不过是大致流程。

如下创建一个 id 为 syrdbt 的 Bean 实例,你需要指明它是哪一个类,这里指明为 com.study.syrdbt.entity.People,然后就可以通过这个目录位置,通过反射创建实例,并且调用其 set 方法注入设置的两个值 name=‘syrdbt’, age=233 。

<bean id="syrdbt" class="com.study.syrdbt.entity.People">
        <property name="name" value="syrdbt"></property>
        <property name="age" value="23"></property>
    </bean>

做一个小小的测试,我们注释了无参构造函数,无法进行属性注入了,因为无法生成实例,再去调用 set 方法。

Spring  IoC(控制反转)、DI(依赖注入)_xml_02


在进行如下修改,我们对 setName 方法进行参数打印,并注释掉了 setAge 方法,如下图所示,我们成功调用了 setName 方法。

Spring  IoC(控制反转)、DI(依赖注入)_属性注入_03


如下图所示:找不到 age 的 set 方法,无法进行属性注入。

Spring  IoC(控制反转)、DI(依赖注入)_xml_04

参考文献

  • 精通 Spring 4.x 企业应用开发实战 陈雄华老师、林开雄老师、文建国老师
  • Spring 实战第 4 版
  • Spring 中文官方文档


举报

相关推荐

0 条评论