# IOC-1

# 引言

::: info

ioc 的简单实现

:::

# Before

在之前学习的最基础的 Servlet 为基础的 JavaWeb 构建中,一条功能实现被架构分成了很多层。

上图为博主在数据库课设中项目的文件结构。dao->service->servlet。其中 dao 层和 service 层有对应的接口和实现。

1. 先创建一个 Dao 层的接口

public interface UserDao {
    void work();
}

2. 然后需要些一个 Dao 层的实现类

public class UserDaoImpl implements UserDao{
    public void work() {
        System.out.println("work");
    }
}

3. 然后写 Service 层的接口

public interface UserService {
    void work();
}

4. 最后是 Service 的实现类

public class UserServiceImpl implements UserService {
   private UserDao userDao = new UserDaoImpl();
   @Override
   public void work() {
       userDao.work();
  }
}

这样才算完成了一条 service。

但是有个问题就是,一个接口本来就是设计来就是为了一个或多个实现类来实现,如果之后我们用不同的实现类。具体来说我们需要写一个 Mysql 的接口或者 Oracle 的,那么该怎么写?

我们就需要在增加一个 Dao 层的实现类和一个 Service 层的一个实现类,会让我们增加很多相似的代码,同时增加程序的耦合性,维护性非常的大,这个代码它多捞啊。

# After

我们可以设置一个不去留下一个具体的 Service 实现,我们留下一个接口,利用 set 方法。

public class UserServiceImpl implements UserService {
   private UserDao userDao;
	// 利用 set 实现
   public void setUserDao(UserDao userDao) {
       this.userDao = userDao;
  }
   @Override
   public void work() {
       userDao.work();
  }
}

然后在测试类中

@Test
public void test(){
   UserServiceImpl service = new UserServiceImpl();
   //Mysql 去实现
   service.setUserDao( new UserDaoMySqlImpl() );
   service.work();
   //Oracle 去实现
   service.setUserDao( new UserDaoOracleImpl() );
   service.work();
}

虽然现在感觉上并没有什么区别,但是有个关键的区别就是并不是系统直接为我们创建了对象,而是我们通过自己自行创建。所以以后程序只需要留下一个接口,然后我们自己来进行实现。这就是 IOC 的原型。

# IOC 本质

控制反转(Inversion of Control,缩写为 IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称 DI),还有一种方式叫 “依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

IoC 是 Spring 框架的核心内容,使用多种方式完美的实现了 IoC,可以使用 XML 配置,也可以使用注解,新版本的 Spring 也可以零配置实现 IoC。

Spring 容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从 Ioc 容器中取出需要的对象。

采用 XML 方式配置 Bean 的时候,Bean 的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean 的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

控制反转是一种通过描述(XML 或注解)并通过第三方去生产或获取特定对象的方式。在 Spring 中实现控制反转的是 IoC 容器,其实现方法是依赖注入(Dependency Injection,DI)。

# 简单快速体验 Spring

# 简单的实现

1. 必须的 jar 包

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.6.RELEASE</version>
</dependency>

2. 编写一个实体类

public class User {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void show(){
        System.out.println("show  "+name);
    }
}

3. 然后编写一个 xml 文件,这里命名为 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
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user" class="com.Meteor.pojo.User">
        <property name="name" value="Meteor"/>
    </bean>
   
</beans>

4. 测试

@Test
public void test(){
   // 解析 beans.xml 文件,生成管理相应的 Bean 对象
   ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
   //getBean : 参数即为 spring 配置文件中 bean 的 id .
   User user = (User) context.getBean("user");
   user.show();
}

这里我们就可以看出控制反转的意思了。

控制:以前都是程序控制对象的创建,但是这里我们是通过 spring 来创建对象。

反转:程序不再创建对象,而是变成被动的接受。

# 之前问题 Spring 实现

1. 编写 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
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="mysqlImpl" class="com.Meteor.dao.UserDaoMysqlImpl"/>
    <bean id="oracleImpl" class="com.Meteor.dao.UserDaoOracleImpl"/>
    <bean id="UserServiceImpl" class="com.Meteor.service.UserServiceImpl">
        <property name="userDao" ref="mysqlImpl"/>
    </bean>
    <!--
       ref: 引用 Spring 容器中创建好的的对象
       value: 具体的值,基本数据类型
     -->
</beans>

2. 测试

@Test
public void test(){
   ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
   UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean("UserServiceImpl");
   serviceImpl.work();
}