Spring 5.3.9

环境

  • JDK 1.8
  • Maven 3.6.3
  • IntelliJ IDEA 2020

知识

  • Java基础
  • Maven
  • JUnit
1、简介

1.1、什么是Spring

【Spring】一、简介和IOC理论推导_maven

Spring框架是由于软件开发的复杂性而创建的。

  1. 使用基本的JavaBean来代替复杂的 EJB (Enterprise Java Beans);
  2. 不仅可用于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益;
  3. 理念:使现有的技术更容易使用,整合了很多现有的技术框架。

有关起源

  • 2002年,首次推出了Spring框架的雏形:interface 21框架
  • 2004年3月24日,Spring框架以interface 21框架为基础重新设计,发布了1.0正式版;
  • Rod JohnsonSpring Framework创始人,在悉尼大学获得了计算机学位和音乐学位,更是拿到了音乐学的博士学位。

1.2、为什么要使用Spring

Spring是一个轻量级的控制反转、面向切面编程的容器。

  • 优点:开源、免费、轻量级、非入侵式;
  • 特性:控制反转,面向切面编程
  • 支持事务处理、整合框架

1.3、组成

【Spring】一、简介和IOC理论推导_maven_02

1.4、搭建工程

  1. 创建一个不带模板的Maven空项目
  2. 删除src目录,作为项目的父工程;
  3. 导入Maven依赖
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.9</version> </dependency>
  4. 创建模块,完成开发准备工作。
2、IOC理论推导

2.1、问题引入

在传统的web开发中,要实现一个业务,需要编写以下程序:

  1. XxxDao:接口
  2. XxxDaoImpl:接口实现类
  3. XxxService:业务接口
  4. XxxServiceImpl:业务实现类

2.1.1、需求:输出用户信息

  1. UserDao
    public interface UserDao { /** * 获取用户信息 */ void getUserInfo(); }
  2. UserDaoImpl
    public class UserDaoImpl implements UserDao{ @Override public void getUserInfo() { System.out.println("这里是用户信息"); } }
  3. UserService
    public interface UserService { /** * 获取默认用户信息 */ void getUserInfo(); }
  4. UserServiceImpl
    public class UserServiceImpl implements UserService { /** * Service层:调用Dao层 */ private UserDao userDao = new UserDaoImpl(); @Override public void getUserInfo() { userDao.getUserInfo(); } }
  5. Test
    @Test public void test() { UserService userService = new UserServiceImpl(); userService.getUserInfo(); }

【Spring】一、简介和IOC理论推导_maven_03

业务流程:Test相当于测试用户,用户访问​​Service层​​,​​Service层​​再去调用​​DAO层​​的方法。即用户不会直接访问到​​DAO层​​。

2.1.2、新需求:增加新用户

  • 新的接口实现类
    public class UserDaoMySqlImpl implements UserDao{ @Override public void getUserInfo() { System.out.println("这里是MySQL用户信息"); } }
  • 修改原本的代码
    private UserDao userDao = new UserDaoImpl(); // 需要改为 private UserDao userDao = new UserDaoMySqlImpl();

分析:

  1. ​UserServiceImpl​​中的​​userDao​​是固定的,相当于“锁定”了具体一类用户的使用;
  2. 若增加新用户,即新建一个​​接口实现类​​。
  • 需要修改​​UserServiceImpl​​中​​userDao​​的值,才能供新用户的使用;
  • 代码强耦合,复用性低,维护成本高。
  • 在当前情况下,用户的需求可能会影响原来的代码:客户提出需求,程序员需要根据不同需求来修改原先的代码;
  • 需要找到一种方案,让程序能够自行应对客户的不同需求。

原因:究其根本,是因为​​UserServiceImpl​​中的​​userDao​​是固定值,“锁定”了具体一类用户的使用。如果能够使​​userDao​​可以根据不同用户来动态实现值的注入,就能解决这个难题。

2.2、解决问题

2.2.1、方案

userServiceImpl做如下修改:

  1. 去掉声明userDao时的赋值操作;
  2. 通过setter()实现动态赋值。
    /** * Service层:调用Dao层 */ private UserDao userDao; /** * 根据用户,为userDao动态赋值 * * @param userDao 具体用户 */ public void setUserDao(UserDao userDao) { this.userDao = userDao; }

测试

@Test
public void test() {
// 多态:父类引用指向子类对象
UserService userService = new UserServiceImpl();
// 由于父类不能调子类方法,所以需要先强转成子类才可以调用方法
((UserServiceImpl) userService).setUserDao(new UserDaoImpl());

userService.getUserInfo();
}


【Spring】一、简介和IOC理论推导_控制反转_04

@Test
public void test() {
// 多态:父类引用指向子类对象
UserService userService = new UserServiceImpl();
// 由于父类不能调子类方法,所以需要先强转成子类才可以调用方法
((UserServiceImpl) userService).setUserDao(new UserDaoMySqlImpl());

userService.getUserInfo();
}


【Spring】一、简介和IOC理论推导_mysql_05

分析

  1. ​UserServiceImpl​​中的​​userDao​​是动态注入的,由具体用户选择使用;
  2. 若增加新用户,即新建一个​​接口实现类​​。
  • 不再需要修改​​UserServiceImpl​​中​​userDao​​的值;
  • 解耦,提高复用性,降低维护成本。
  • 在这种情况下,用户的需求不影响原来的代码,客户提出需求,程序员不再需要修改原先的代码,而是由程序自行应对不同需求;

2.2.2、对比

  • 原来的业务:主动权在程序上。
  1. 程序主动创建对象;
  2. 需求有变动的话,程序员需要修改对象的创建;
  • 现在的业务:主动权在用户。
  1. 使用setter注入对象,程序不再具有主动性,变成被动的接收对象;
  2. 接收对象后,由第三方动态地为对象注入值;
  3. 需求有变动的话,由用户自行选择设置。

举一个生活中的例子:你请客人吃饭。

  • 原来的方式:你决定菜品,亲自下厨。
  1. 你主动决定要请客人吃的菜品,去市场先买好菜;
  2. 来了新客人,要吃不同的菜,你就需要重新去市场买菜。
  • 现在的方式:客人决定菜品,叫饭店做。
  1. 你不事先备菜,而是听客人要吃的菜品;
  2. 知道客人要吃的菜品,你打电话给饭店点菜;
  3. 来了新客人,要吃不同的菜,你就再打给饭店加菜。
  • 分析
  • 你:程序员、程序;
  • 客人:用户;
  • 饭店:第三方;
  • 菜品:业务需求;
  • 原来的方式:主动权在你手上,但是客人想吃不同菜品,你就要麻烦自己再去备菜;
  • 现在的方式:主动权在客人手上,客人想吃不同菜品,你就打个电话给饭店点菜就好了。

这种思想,从本质上解决了问题,程序员不再需要管理对象的创建,而是由用户自行根据需求选择

这就是IOC思想的原型!

2.3、IOC的本质

控制反转(Inversion of Control)是一种设计思想,通过描述(XML或注解)并通过第三方去获取或生产特定对象。

  • 没有IOC的程序中 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序本身控制;
  • 控制反转后,将对象的创建转移给第三方,即获得依赖对象的方式反转了;

【Spring】一、简介和IOC理论推导_maven_06

IOC是Spring框架的核心内容IOC有多种实现方式:XML配置、注解,甚至零配置实现。

  • 采用XML配置BeanBean的定义和实现分离;
  • 采用注解配置Bean:把二者合为一体,Bean的定义信息以注解的形式定义在实现类中,达到了零配置的目的。

容器工作流程

  1. Spring容器在初始化时先读取配置文件;
  2. Spring容器根据元数据创建并组装Bean对象;
  3. 配置好的系统程序,使用时从容器中获取需要的Bean对象;

【Spring】一、简介和IOC理论推导_控制反转_07

Spring中事项控制反转的是IOC容器,依赖注入(Dependency Injection)是IOC的一种实现方法。