【示例】Spring-IOC理解

前言

本文从常规的开发示例(DAO、Service、Client)入手,逐步体会理解IOC的原理及实现。

文中示例的代码地址:

GitHub https://github.com/Web-Learn-GSF/Java_Learn_Examples
父工程 Java_Framework_Spring

示例 | 常规三层开发示例

层级结构及代码展示

代码层级结构:经典三层:

  • Dao:获取数据库数据,处于数据库和Service层之间(在示例中没有真的获取数据库,仅展示)

  • Service层:业务逻辑实现的地方

  • Client:客户端调用,在这里面就是UserTest

image-20240409212205420

源码实现

DAO | UserDao

public interface UserDao {
   public void getUser();
}

DAO | UserDaoImpl

public class UserDaoImpl implements UserDao {
   @Override
   public void getUser() {
       System.out.println("Dao获取用户数据");
  }
}

Service | UserService

public interface UserService {
   public void getUser();
}

Service | UserServiceImpl

public class UserServiceImpl implements UserService {
   private UserDao userDao = new UserDaoImpl();

   @Override
   public void getUser() {
       userDao.getUser();
  }
}

UserTest

public class UserTest {
    @Test
    public void test(){
        UserService service = new UserServiceImpl();
        service.getUser();
    }
}

增加一个新的实现

增加一个新的实现需要:新增DAO实现、修改Service实现的代码

Dao | UserSqlImpl

public class UserSqlImpl implements UserSql {
   @Override
   public void getUser() {
       System.out.println("Sql获取用户数据");
  }
}

Service | UserServiceImpl

public class UserServiceImpl implements UserService {
    // 原内容
	// private UserDao userDao = new UserDaoImpl();
   	
    // 修改后的内容
    private UserSqlImpl userDao = new UserSqlImpl();

   @Override
   public void getUser() {
       userDao.getUser();
  }
}

思考?

针对常规开发模式,每增加一个源码实现,都需要对服务端实现的代码进行更改,非常麻烦。代码耦合性太高。

怎样降低代码之间的耦合度呢?利用Set函数

添加Set()函数

保持其他内容不变,修改服务端实现类的代码内容:

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

   @Override
   public void getUser() {
       userDao.getUser();
  }
}

修改客户端代码实现如下:

@Test
public void test(){
   
    UserServiceImpl service = new UserServiceImpl();
    // Dao实现
    service.setUserDao( new UserDaoImpl() );
    service.getUser();

    //Sql实现
    service.setUserDao( new UserSqlImpl() );
    service.getUser();
}

思考?

可以看到,针对新的源码实现,不再需要修改业务端的逻辑,仅是在客户端,通过传入不同的业务端实现对象,即可完成更改。

添加set函数前后的对比:

添加前 添加后(IOC原型)
对象创建主动权在程序,在Service层 对象创建主动权在调用者,在Client层
对象是写死的,更改实现对象,就需要更改业务端Service代码 对象是通过接口动态接收的,调用者给什么,就实现什么

理解 | IOC

在没有应用IOC思想的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制。

在使用IOC的思想后,控制反转,将对象的创建转移给第三方,实现解耦。

image-20231113224431882

示例 | 修改上述示例为IOC实现

引入xml配置文件

image-20240409215342042

<?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.example.Dao.UserDaoImpl"/>
    <bean id="DaoImpl" class="com.example.Dao.UserSqlImpl"/>

    <!--业务端代码实现-->
    <bean id="ServiceImpl" class="com.example.Service.UserServiceImpl">
        <!--注意: 这里的name并不是属性, 而是UserServiceImpl实现类里面setUserDao方法中set后面的那部分, 其中首字母要小写-->
        <!--该方法的参数是引用另外一个bean, 这里不能用value,而是用ref:一个已经存在的对象-->
        <property name="userDao" ref="MysqlImpl"/>
    </bean>

</beans>

修改客户端的实现

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

思考?

可以看到,使用Spring的IOC容器后,我们并没有在客户端中实例化Dao层对象,也没有把Dao的实例化对象传递给Service,但是完成了结果输出。

我们可以思考下面两个问题:

  • Dao层的实例化对象由谁创建?
由Spring创建的
  • Service层userDao这个对象属性是怎么设置的?
通过DI-属性注入的方式实现外部注入

	- 外部:指xml配置文件
	- 属性注入:本质是利用类的set()方法

上述示例,可以总结为一句话:

  • IoC(Inversion of Control,控制反转) 是一种设计思想,DI(Dependency Injection,依赖注入) 是实现IoC的一种方法
  • 在Spring中,通过DI,可以将对象的创建和管理交由Spring来完成

相关推荐

  1. Spring中的IOC与AOP的理解(1)

    2024-04-10 10:28:02       49 阅读
  2. 说下你对Spring IOC理解

    2024-04-10 10:28:02       29 阅读
  3. Spring IOC

    2024-04-10 10:28:02       58 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-10 10:28:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-10 10:28:02       101 阅读
  3. 在Django里面运行非项目文件

    2024-04-10 10:28:02       82 阅读
  4. Python语言-面向对象

    2024-04-10 10:28:02       91 阅读

热门阅读

  1. pandas习题 028:用命名元组 namedtuple 构造 DataFrame

    2024-04-10 10:28:02       34 阅读
  2. .bat 脚本

    2024-04-10 10:28:02       38 阅读
  3. C#WPF仿苹果的漂亮的工具栏

    2024-04-10 10:28:02       32 阅读
  4. python-pytorch NLP中处理中文的步骤0.5.002

    2024-04-10 10:28:02       29 阅读
  5. 模板的全特化和局部特化

    2024-04-10 10:28:02       44 阅读
  6. 【python】 Django Web框架

    2024-04-10 10:28:02       41 阅读
  7. 客户端(client)fork 一个服务器(server)进程

    2024-04-10 10:28:02       34 阅读
  8. pandas习题 021:根据字符串包含情况查询 Series

    2024-04-10 10:28:02       37 阅读
  9. git reset 的三种模式

    2024-04-10 10:28:02       35 阅读
  10. arcgis10.x创建镶嵌数据集

    2024-04-10 10:28:02       40 阅读